Skip to content

ci(release): allow publishing one package on its own and fix Enterprise E2E dispatch - #67

Merged
bluestreak01 merged 7 commits into
mainfrom
ci/single-package-release
Sep 30, 2026
Merged

bluestreak01 merged 7 commits into
mainfrom
ci/single-package-release

Conversation

@glasstiger

@glasstiger glasstiger commented Sep 29, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Two CI changes that don't affect the published packages.

Publish one package on its own

publish.yml gains a packages input (both by default, nodejs, or browser). This lets one package ship before the other, for example when the browser client depends on server support that hasn't shipped yet.

  • The two manifests must still carry the same version.
  • scripts/check-release-versions.mjs checks only the selected packages against npm, so the other package can follow later under the same version with its own dispatch.
  • A both dispatch behaves as before: it refuses a forgotten bump, and it resumes a partial release only when the published package's npm gitHead matches the commit being dispatched.
  • A single-package dispatch of a package that is already on npm is refused. The error names the package that is still missing and the packages value that publishes it.
  • Lint, typecheck, test and artifact checks still cover both packages whatever the selection.
  • CONTRIBUTING.md documents the procedure.

Enterprise E2E dispatch

  • Azure rejects an empty string for javascriptClientPrNumber with HTTP 400, which broke every push, schedule and workflow_dispatch run. The parameter is now omitted when there is no pull request, so the pipeline default applies.
  • When an Azure call fails, the step now prints Azure's error message, or the start of the response body. Previously curl -f together with set -e exited without showing why.

Testing

  • test/release-version.test.ts now runs the gate against fixture manifests instead of the repository's own. It covers:
    • single-package dispatches
    • the already-published refusal and its hint, naming whichever package is still missing
    • the refusal when every package is already published, for each selection
    • unknown selections
    • lockstep enforcement for every selection
  • Every combination of selection, registry state and gitHead was run against a fake npm registry, comparing the head and base scripts.
  • The jq request body and the error helper were run against JSON, null, array, HTML and empty responses.

… E2E dispatch

Azure rejects an empty string for the javascriptClientPrNumber template
parameter, which failed every push and schedule dispatch. Omit it when there
is no pull request, and print Azure's error message when a call fails instead
of exiting silently under set -e.
Add a packages input (both, nodejs, browser) to the publish workflow. The
release gate keeps the manifests in lockstep but checks only the selected
packages against npm, so one package can ship first and the other can
follow later under the same version.
@glasstiger

Copy link
Copy Markdown
Collaborator Author

Review: approve (no Critical or Moderate findings, one Minor)

Reviewed head 07c50fc7 against base b94ab855. The PR only touches CI, docs and the release script; nothing under packages/*/src or the published packages changes.

The title and both commits follow Conventional Commits, and every procedure described in CONTRIBUTING.md matches what the script and workflow actually do.

Evidence

  • Default release unchanged: I ran the base and head versions of check-release-versions.mjs against a fake npm registry, covering all 24 combinations of which packages are published and which commit each came from. With RELEASE_PACKAGES unset or set to both, head exits the same way as base in every case.
  • Single-package releases: nodejs and browser gate only the selected package. The manifest version-match check still runs for every selection, including the drifted-manifest test.
  • Gate and publish steps agree: both read inputs.packages, which is a choice input, and the script rejects any unknown value before calling npm.
  • Azure request body: the jq filter parses with its embedded comments and leaves out javascriptClientPrNumber when it's empty. Pull-request runs still send the PR number, as before.
  • azure_error(): tested against JSON, null, empty, array, HTML and non-string message bodies. It prints Azure's message or falls back to the start of the body. The Azure PAT is never printed.
  • Tests: test/release-version.test.ts passes at head (3/3), and tsc on the test config reports nothing for it.

Minor

  • test/release-version.test.ts:104: the test named "publishes a selected package on its own" also asserts that an already-published nodejs dispatch is refused and that an unknown RELEASE_PACKAGES value is rejected. Splitting it into separate it blocks would make the names accurate.

Test coverage

Two refusal messages for single-package dispatches have no test:

  • the "Bump the version first." message when nothing else is missing;
  • the case where the browser package is published and the hint should say packages=nodejs.

Both still exit 1, so only the hint text is unguarded. The fake npm could take its published list from an environment variable, as it already does for FAKE_NPM_GIT_HEAD, to make these easy to test. Not blocking.

Trade-off

A single-package dispatch never checks which commit the other package was published from. So browser@V can ship from a later commit than nodejs@V, even after a both dispatch that failed partway. This is the documented "follow later from a later commit" flow, and npm never overwrites a published version. The catch is that a shared version number no longer guarantees both packages were built from the same client-core code.

Not verified

Whether the Enterprise Azure pipeline has a default for javascriptClientPrNumber; that pipeline's code isn't in this repo. If it had none, push and schedule dispatches would still fail, but they fail at base too.

Submodules: none changed.

Only the browser selection had a passing single-package case, so a broken nodejs selection kept every test green while refusing a real Node-only release.
…ection

When curl fails before Azure answers, or Azure sends no body, the step printed 'Azure DevOps rejected ...:' with an empty detail. Point at curl's own error line instead.
@glasstiger

Copy link
Copy Markdown
Collaborator Author

Review: approve (no Critical or Moderate findings, one Minor)

Reviewed head 208a7de5 against base b94ab855. Nothing under packages/*/src changes, so the published package contents are unaffected. The split tests and the refusal-hint tests asked for in the earlier review are in place.

Evidence

  • Release gate, head vs base. I ran both versions of check-release-versions.mjs against a fake npm that returns E404 for unpublished packages. This covered 48 combinations of the packages value (unset, both, nodejs, browser), registry state (none, nodejs, browser, both published) and gitHead (same, other, missing).
    • Unset and both exit exactly as base does in all 24 of their combinations.
    • A single-package dispatch differs from base only where intended:
      • it passes when the other package is already on npm from a different or missing gitHead;
      • it refuses when the selected package is already published.
    • The script's selection always matches the if: conditions on the publish steps.
  • Enterprise dispatch step. I extracted the step from build.yml and ran it against a local HTTP server.
    • Without a PR number the request body omits javascriptClientPrNumber; with a PR number the field is included.
    • A 400 with a JSON body prints Azure's message, and a 401 with an HTML body prints the start of the body.
    • A 500 with no body, or a refused connection, prints the "failed without a response body" message.
    • Every failure exits 1, and the PAT is never printed.
  • Tests. test/release-version.test.ts passes 6/6 at head. Each assertion reaches the script branch it names and would fail if that branch regressed. This includes the lockstep check for every selection and the absence of a hint when both packages are already published.

Minor

  • CONTRIBUTING.md:135 is 86 characters wide, while the lines around it wrap at about 72–80. Re-wrapping the paragraph fixes it. This file isn't covered by format:check, and the base version already fails Prettier on its tables.

Test coverage

The test gate passes with no gaps admitted. The if: conditions in publish.yml and the build.yml shell have no automated tests; I checked them by hand as described above.

Trade-off (documented)

A single-package dispatch never checks which commit the other package came from. As a result, nodejs@V and browser@V may be built from different client-core commits. CONTRIBUTING.md describes this as the intended flow.

Not verified

Whether the Enterprise Azure pipeline has a default for javascriptClientPrNumber; its definition isn't in this repo. If it has none, non-PR runs will still fail, as they already do at base, but the new error output will now show the reason.

Submodules: none changed.

@bluestreak01 bluestreak01 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approve

Level 3 review: b94ab855 → 208a7de5. No admitted findings or demonstrated regressions.

Validation

  • Release tests: 6/6 passed.
  • Test typecheck and changed-test formatting passed.
  • 72 head/base release scenarios checked; default-release decisions preserved.
  • 58 local Azure-step executions checked payloads and failure handling.
  • Reverting production changes and mutating key guards made the tests fail.

Coverage and scope

  • Test gate: pass; 0 admitted coverage gaps.
  • Severity: 0 Critical / 0 Moderate / 0 Minor.
  • Findings: 0 in-diff / 0 out-of-diff breakage.
  • Submodules: none.

Documented trade-off: separately released packages can share a version while containing different commits.

Live Azure pipeline defaults remain unverified; full integration/browser suites were not run locally. The working tree is unchanged, and temporary worktrees were removed.

@bluestreak01
bluestreak01 merged commit a658130 into main Sep 30, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants