Skip to content

Bump @types/node from 25.0.3 to 26.4.0 (#74) #122

Bump @types/node from 25.0.3 to 26.4.0 (#74)

Bump @types/node from 25.0.3 to 26.4.0 (#74) #122

Workflow file for this run

name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
permissions:
contents: read
jobs:
ci:
runs-on: ubuntu-latest
env:
# The Artifactory steps below are opt-in and self-disabling, and this one
# expression is the reason. They run only when the repository variable
# JF_URL is set *and* the triggering event is allowed to see repository
# secrets. Unset JF_URL and this workflow behaves exactly as it did before
# Artifactory existed: plain `npm ci` against registry.npmjs.org.
#
# Two separate cases lose access to secrets, and both must be excluded or
# `jf` fails authentication:
#
# 1. Forked pull requests are never given secrets. Without this, every
# outside contribution to a public Apache-2.0 project would fail -
# unacceptable on its own, and also counts against the "zero
# JFrog-caused build failures" criterion the JFrog evaluation hangs
# on (Lab271/labs-jfrog-poc docs/06-evaluation.md, criterion 3b).
#
# 2. Dependabot pull requests. These are the non-obvious ones: the
# branch lives in *this* repo, so the fork check above passes, but a
# dependabot-triggered run is given the `dependabot` secret store
# rather than the Actions one, and JF_ACCESS_TOKEN is not in it. The
# `jf` CLI then talks to Artifactory unauthenticated and gets a flat
# 401 "Authentication is required" before a single package resolves,
# taking down #65, #66, #67 and #68 together. Note that `vars` ARE
# visible to dependabot, which is why JF_URL alone cannot gate this.
#
# Adding JF_ACCESS_TOKEN as a dependabot secret would also clear the 401,
# but the token is deliberately not handed to runs built from an automated
# dependency bump. These PRs resolve from registry.npmjs.org instead;
# what they change is the lockfile, and main re-resolves it through
# Artifactory on merge.
JFROG_ENABLED: ${{ vars.JF_URL != '' && github.actor != 'dependabot[bot]' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v4
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: '20'
cache: 'npm'
# `custom-server-id` has to be `schubergphilis` because .jfrog/projects/npm.yaml
# names that server ID; the action would otherwise register a generated one and
# every `jf npm` command would fail with "server ID does not exist".
#
# `disable-auto-build-publish` matters more than it looks. By default this action's
# post-job step publishes any build-info that was collected but not published -
# without a project key. On this tenant we are project admin on `lab`, not platform
# admin, so an unscoped publish is a flat 403 against the platform-level
# artifactory-build-info repository, and it would fail the job *after* the tests
# already passed. We publish explicitly below, with --project.
- name: Set up JFrog CLI
if: env.JFROG_ENABLED == 'true'
uses: jfrog/setup-jfrog-cli@deda456d982fc5e9a7a020b63eb0d2968aedd33e # v5.1.0
env:
JF_URL: ${{ vars.JF_URL }}
JF_ACCESS_TOKEN: ${{ secrets.JF_ACCESS_TOKEN }}
with:
version: 2.122.0
custom-server-id: schubergphilis
disable-auto-build-publish: true
# Two variants of the same install, selected by JFROG_ENABLED. `jf npm ci` is
# `npm ci` with dependency collection bolted on: same lockfile, same result on
# disk, plus a build-info record of all 615 resolved packages. The build number
# is prefixed `ci-` on purpose - release.yml uses the git tag as its build number,
# and github.run_number is a per-workflow counter, so bare numbers from the two
# workflows would eventually collide on the same build name.
- name: Install dependencies (through Artifactory)
if: env.JFROG_ENABLED == 'true'
run: jf npm ci --build-name=slidecue --build-number=ci-${{ github.run_number }} --project=${{ vars.JF_PROJECT }}
- name: Install dependencies
if: env.JFROG_ENABLED != 'true'
run: npm ci
# vitest is intentionally not a package.json dependency so that the
# committed package-lock.json stays in sync for `npm ci` (used by the
# release workflow). Install it transiently for the test run.
#
# Deliberately no --build-name/--build-number here: this resolves outside the
# lockfile and is not part of what the package ships, so recording it would
# pollute the dependency tree that Xray reasons about. It still goes through
# lab-npm-dev, which is the point - it was the last direct hit on
# registry.npmjs.org in this workflow.
- name: Add test runner (through Artifactory)
if: env.JFROG_ENABLED == 'true'
run: jf npm install vitest@^4 --no-save
- name: Add test runner
if: env.JFROG_ENABLED != 'true'
run: npm install --no-save vitest@^4
# Added with the eslint config itself (#63). `npm run lint` was broken for
# the entire life of the repo and nothing caught it, because no workflow
# ever invoked it - a lint script no job runs is a lint script that rots.
# Warnings do not fail the build; errors do.
- name: Lint
run: npm run lint
- name: Type check
run: npm run typecheck
- name: Unit tests
run: npm test
# Regression guard. `npm pack` once produced a 3.9 MB tarball containing no
# application code at all (see #59), and nothing here would have noticed --
# CI never packs, and the release workflow ships electron-builder installers
# rather than the npm tarball. So assert the contents directly.
#
# This inspects the real tarball rather than `npm pack --dry-run --json`,
# because `prepack` runs `npm run build` and electron-vite writes its progress
# to stdout, which corrupts the `--json` output.
#
# It doubles as the only check that `npm run build` still succeeds, since
# `prepack` has to run before a tarball exists at all.
- name: Pack check
run: |
mkdir -p /tmp/packcheck
npm pack --pack-destination /tmp/packcheck
tar -tzf /tmp/packcheck/*.tgz | sed 's|^package/||' | sort > /tmp/packcheck/list.txt
echo "Packed files:"
sed 's/^/ /' /tmp/packcheck/list.txt
status=0
# Must ship: the entry point npm advertises, plus the renderer, preload and
# web remote UI the app loads at runtime.
for required in \
"$(node -p 'require("./package.json").main')" \
out/preload/index.js \
out/renderer/index.html \
resources/remote/index.html
do
if ! grep -qxF "$required" /tmp/packcheck/list.txt; then
echo "::error::npm pack is missing $required"
status=1
fi
done
# Must not ship: design source and application source. Both were packed at
# some point, icon/ because npm packs everything by default and src/ never,
# because a stale .npmignore excluded it. Catch a slide back either way.
for forbidden in icon/ src/ node_modules/ test/
do
if grep -q "^$forbidden" /tmp/packcheck/list.txt; then
echo "::error::npm pack should not ship $forbidden"
status=1
fi
done
exit $status
# Last, so a build whose tests or pack check failed never gets a published
# build record.
# With auto-publish disabled above, a failed job simply leaves the collected
# build-info on the runner and it disappears with the runner.
#
# `build-add-git` is not optional bookkeeping: `jf rt build-publish` does NOT
# collect VCS information by itself (verified - build-info comes back with
# "vcs": []), and without it there is no commit link, which is exactly the
# artifact -> deps -> commit chain this whole exercise is for. On a GitHub
# runner HEAD is detached, so `branch` comes back empty; the revision, which
# is the part that matters, is correct.
- name: Publish build-info
if: env.JFROG_ENABLED == 'true'
run: |
jf rt build-add-git slidecue ci-${{ github.run_number }} --project=${{ vars.JF_PROJECT }}
jf rt build-publish slidecue ci-${{ github.run_number }} --project=${{ vars.JF_PROJECT }}