ci: build and test the extension on push - #35
Merged
Conversation
Adds the repo's first CI. Runs the checks the repo already defines -- eslint, the tsconfig.test.json type-check, and the vitest suite -- then builds both store targets the way the Makefile does (npm run build, npm run build:firefox) and asserts each produced a real zip. No secrets: every dependency, @urnetwork/sdk-js and @urnetwork/localizations included, resolves from the public npm registry, and tests/setup.ts stubs fetch so the suite is offline.
`eslint .` fails on a fresh checkout of main with 12 pre-existing errors (10 no-explicit-any, one unused binding, two react-hooks ref-during-render in elements/src), which stopped the run before the tests or either build ran at all. Same treatment connect's workflow gives its known-flaky extender test: the step still runs and still reports, but a pre-existing failure does not gate the build-and-test this workflow exists for. Drop continue-on-error once main lints clean.
Two things the workflow was missing and two the comment got wrong.
Missing:
- timeout-minutes: 15 on the job. The run takes ~1 minute, so this is
purely a hang guard -- without it a wedged npm install would hold a
runner for the 6-hour default.
- a concurrency group keyed on workflow+ref with cancel-in-progress.
Pushing twice to a PR branch otherwise leaves the first run racing
the second for no reason. This matches the shape the other node CI
in the org uses.
Corrected, both in the comment above the non-blocking lint step:
- the count is 9 @typescript-eslint/no-explicit-any, not 10. The 12th
error is the second of the two react-hooks errors; the tally was off
by one because the react-hooks pair was undercounted.
- the two "Cannot access refs during render" errors are in this repo's
own src/utils/use-connection-manager.ts, at lines 27-28 where
authFnRef.current and removeFnRef.current are assigned during render
-- NOT in elements/src. elements/ is linted (eslint.config.js only
globalIgnores dist, dist-firefox and elements/dist) but contributes
zero of the 12, so pointing a maintainer at it would send them to
the wrong file.
The comment now also names the difference from the connect/test.yml
precedent it borrows: connect's non-blocking step covers a flaky test,
this one covers deterministic style debt, so it is red every run until
someone fixes it. A permanently red step is easier to stop noticing than
a sometimes-red one, and that is worth saying out loud next to it.
Also names vitest 4's ^20 || ^22 || >=24 alongside vite 7's floor, since
vitest is the constraint that actually excludes odd majors, and switches
the workflow name to the em dash the sibling repos use.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MAXFxG1EK4jTxQ1iW73BUr
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
First CI for this repo: build and test on every push and PR to
main, plus manual dispatch. One file,.github/workflows/build-and-test.yml, nothing else changes.It is green, and it is fast: the whole job takes about a minute.
What it runs
One
ubuntu-latestjob, using the repo's own entry points:npm ci --no-audit --no-fundnpm run lintnpm run test:typesnpm testnpm run buildnpm run build:firefoxactions/upload-artifact@v4test:typesis checked separately becausetsconfig.test.jsonis not referenced fromtsconfig.json— thetsc -binsidenpm run buildnever seestests/.test.shchecks it separately for the same reason. The two build commands are exactly what theMakefileruns.The job carries
timeout-minutes: 15(a hang guard, not a budget — it finishes in ~1 min) and aconcurrencygroup keyed on workflow + ref withcancel-in-progress, so pushing twice to a branch does not leave two runs racing.The one judgement call: lint does not gate
eslint .fails on a fresh checkout ofmainwith 12 errors that predate this PR:@typescript-eslint/no-explicit-any—src/background/index.ts:17,21,110,src/utils/connection-manager.ts:61,src/utils/kill-switch-apply.ts:9,src/utils/proxy-manager.ts:39,40,src/utils/sso.ts:51,src/utils/use-provider-list-enhanced.ts:193_tab—src/background/index.ts:126src/utils/use-connection-manager.ts:27-28, whereauthFnRef.currentandremoveFnRef.currentare assigned during renderNone are auto-fixable, so gating lint means real code changes. The first push of this workflow proved the cost of gating: lint failed and the tests and both builds never ran at all.
So lint gets the same mechanism
connect/test.ymlgives its non-blocking extender step — it still runs, still reports in the log, but a pre-existing failure is not allowed to gate the build-and-test this workflow exists for. One honest difference from that precedent, called out in the file too: connect's step covers a genuinely flaky test, this one covers deterministic debt, so it will be red on every single run until someone fixes it, and a permanently red step is easier to stop noticing than a sometimes-red one.Maintainer decision: leave it reported-but-non-blocking as shipped, or fix the 12 on
mainfirst and dropcontinue-on-error. The comment in the file says to drop it oncemainlints clean. Happy to flip it.No secrets
Nothing here needs a credential, and nothing is skipped to avoid one:
@urnetwork/sdk-js(0.0.1-beta.5) and@urnetwork/localizations(0.0.6) are public on registry.npmjs.org — every entry inpackage-lock.jsonresolves from that one registry, andnpm ciran clean with no token.tests/setup.tsstubsfetchto reject, so a leaked network call fails loudly rather than reachingapi.bringyour.com.npm publish, no release. The two zips are a CI artifact only.Node version
package.jsondeclares noenginesand nopackageManager, so the repo pins nothing itself. The release pipeline (build/all/run.sh) gates on node 24.14.1 / npm 11.11.0, but that is a whole-pipeline reproducibility gate that fires once before any repo is pulled. For this repo alone the binding floors are vite 7's^20.19.0 || >=22.12.0and vitest 4's^20 || ^22 || >=24— together, node^20.19 || ^22.12 || >=24. The workflow pins the node 24 major to stay on the line the pipeline ships from, without pretending the patch matters.Note this differs from
web/build.yml'snode-version: latest, which is unpinned and drifts onto whatever shipped that week, including non-LTS odd majors.lts/*would also satisfy the floors if you prefer that.One known divergence from the release build
build.shrsyncs the siblinglocalizationscheckout over the installed package before building, because for a0.0.xdependency npm treats^as exact — a key added to the store is invisible until the package is republished and the dependency bumped. CI has no sibling checkout, soscripts/build-locales.jstakes its own documented fallback and uses published@urnetwork/localizations@0.0.6. The build is complete and real; it just validates against the published key set, so CI will not catch localization key drift (registrylatestis already 0.0.7 against the locked 0.0.6).Closing that gap is possible but is not a one-liner:
localizations/index.jsimportsjs-yamlas a bare specifier, and Node resolves those only up ancestor directories, so a bare sibling clone cannot see this repo'snode_modules— andresolveLoadAllKeysdoes itsawait import(siblingIndex)with no try/catch, so it would fail the prebuild rather than fall back. It needs the clone andnpm ciinside it. Deliberately left out of a first CI to keep the workflow small; say the word and I will add it.What this deliberately does not do
No release, no signing, no store/AMO upload, no publish, no secrets, and no browser-driven end-to-end tests. Purely: does it install, type-check, test, and build for both targets.
Draft: opened for review, not to merge as-is.