Skip to content

feat: add version-specific Azure hotfix publishing - #7765

Open
Jane Chu (janechu) wants to merge 6 commits into
mainfrom
users/janechu/tag-based-hotfix-publishing
Open

Jane Chu (janechu) wants to merge 6 commits into
mainfrom
users/janechu/tag-based-hotfix-publishing

Conversation

@janechu

@janechu Jane Chu (janechu) commented Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

Pull Request

📖 Description

Add a version-specific hotfix publishing path that never creates or downloads GitHub Releases.

  • Introduce a manual Azure pipeline targeting an explicitly pushed non-main hotfixBranch, whose tip must match the reviewed hotfix/<package>_v<version> tag descended from a published baseline. Transfer only the selected package and paired crates through a governed Azure pipeline artifact.
  • Every new, valid, approved run publishes the pinned maintenance-branch snapshot; main supplies central tooling only. There is no build-only switch. Reuse FAST.Release.PipelineTemplate.yml@fastPipelines with an explicit maintenance npm channel and strict publishing failures, rather than duplicating ordinary CD's ESRP tasks.
  • Verify source/provenance, archive identities, hashes, and registry state; require every selected version to be unused and create a completion marker only after successful verification.
  • Share release metadata helpers and exclude hotfix-reserved versions from both ordinary GitHub release creation and nightly Azure discovery.
  • Add 32 Node regressions plus build-tools DESIGN.md/README.md and contributor/operator documentation. Make the branch-from-tag workflow discoverable through Copilot instructions and the shipping skill.

No public package source, package versions, or package export sizes change.

🎫 Issues

No existing issue identified. Implements the hotfix pipeline requested in conversation.

👩‍💻 Reviewer Notes

Merge dependency: the shared release-template update adding backward-compatible npmDistTag and continueOnError parameters must merge before this PR. This consumer continues to reference fastPipelines on main; previews used the prerequisite branch only as a repository-ref override.

The normal nightly release path remains unchanged except for explicit hotfix exclusion. Hotfixes use their own source-tag namespace and Azure artifacts, not ordinary release tags or GitHub release assets.

The required pipeline inputs are baseTag, hotfixBranch, and hotfixTag. Start a maintenance branch from the published tag (never from main), make and review the relevant fix/tests/version changes, then push the branch to origin. A maintainer tags that pushed branch's approved tip and queues the pipeline against it. main and tag refs are rejected as source branches, and the remote branch head must match the reviewed source tag when planning begins.

Azure's branch selector stays on main only for central pipeline tooling; package code is built/tested/packed from the pinned non-main branch snapshot. Historical branches do not need publishing YAML or helper backports. Later branch movement cannot change a planned run, and the source branch does not need to be merged into main. Already-deployed hotfixes still skip publication. The operator guide, shipping skill, and always-applied Copilot instructions document the same process and retain human control over actual publishing.

The hotfix Deploy job now calls the same FAST.Release.PipelineTemplate.yml@fastPipelines publisher as ordinary CD, between preflight and post-publication verification. It supplies npmDistTag: $(npm_config_tag) and continueOnError: false. The template maps the channel to ESRP's productstate; local .npmrc configuration alone does not configure the distribution service. Publication errors remain failures, and a strictly successful registry verification gates the completion marker.

The protected fast-hotfix-publishing variable group now needs only clientId, keyvault, and tenantId. Owners/approvers and npm/crate directory detection are reused from the shared publisher; separate releaseOwners, releaseApprovers, and crate-selection wiring are removed.

Simplified following review: keep npm packages and paired Rust crates, but remove automatic partial-publication reconciliation, pending-asset copies, self-hashed tooling, and the artifact-local .npmrc. ESRP publishes the original artifact folders. Any existing version stops preflight for approved manual recovery, even when its bytes match; post-publication verification requires this exact version's maintenance channel.

All three URL-encoding review comments are addressed with encodeURIComponent, including the mocked registry. A regression checks the complete version and dist-tag URLs independently, and both encoded scoped URL forms returned HTTP 200 against the public npm registry.

This PR does not register or dispatch a publishing pipeline, create real source/deployment tags, create GitHub Releases, publish packages, or change permissions. Activation requires human configuration of the Azure variable group, approved publishing identity, protected-resource approvals/branch control/exclusive lock, and tag permissions. The exact setup and recovery requirements are documented in build/README.md.

📑 Test Plan

Command/check Result
npm run build Passed; all 9 unchanged build tasks reused Lage caches.
npm run test Passed; the build-tools suite executed all 32 tests, with 14 unchanged tasks reusing cached results.
npm run biome:check Passed; checked the 2 revised MJS files.
npm run biome:check -- --staged -- --no-errors-on-unmatched Passed; checked the 2 revised MJS files, including formatting and imports.
npm run format:check Passed; checked all 6 MJS files changed from main.
npm run checkchange Passed; all 4 publishable workspaces have existing CD coverage, and no change files are required for private build tooling/docs/pipeline changes.
node build/scripts/create-github-releases.mjs --check-only Passed; 4 existing normal release tags and 0 missing releases.
GITHUB_REPOSITORY=microsoft/fast node build/scripts/download-github-releases.mjs --check-only Passed; 0 undeployed normal releases.
git diff --check and git diff --cached --check Passed.
Previous revision 0842d7e0b — GitHub/Azure CI and CodeQL Passed; all three reported encoding alerts are fixed and their review threads are resolved. These are historical results, not remote validation of the branch-targeting update.

Azure Pipelines Preview expanded both the three-input hotfix YAML and the existing ordinary CD YAML using the prerequisite shared-template branch as a repository-ref override. Structured checks of the compiled hotfix YAML verified both publishers, the explicit npm productstate, fatal publisher errors, successful-predecessor conditions, preflight/publication/verification ordering, both stages, and verified deployment-marker gating. The ordinary consumer, with no new parameters, retained its unspecified npm productstate and continueOnError: true defaults. The committed resource still targets main, so the template prerequisite must merge first. These were preview-only requests; no pipeline runs were queued.

The 32 tests use temporary repositories/local bare remotes, real npm tarballs, offline Cargo archives, standalone copied verification tools, and mocked registry responses. They cover source materialization/provenance, malformed and moved tags, version-line restrictions, paired crate validation, archive integrity, publish-config overrides, no-GitHub-release routing, always-included publication with central manual/main enforcement, rejection of previously published versions, exact scoped URL encoding, channel rollback/latest rejection, per-registry checksum verification, and verified completion markers.

Branch regressions reject missing/invalid/main/tag-ref inputs, local-only or missing remote branches, branch/tag mismatches, and mismatched publication context before registry access. The successful source-selection test uses a historical branch with no pipeline YAML, accepts refs/heads/..., advances and pushes the branch after planning, and confirms packing still uses the original pinned source. The new required-branch and remote-branch regressions failed before implementation.

The shared-template regression failed before integration and now requires the shared repository/call, explicit channel and strict failure parameters, and absence of duplicated ESRP tasks. The installed ESRP v10 task metadata confirms productstate and waitforreleasecompletion semantics; authenticated EngHub guidance was not accessible.

Lage's cached browser output includes an earlier Firefox retry; these browser tasks were not freshly executed. The initial GitHub CI run failed before project tests when the existing unlocked cargo install wasm-pack resolved a yanked zip dependency. The new hotfix pipeline uses cargo install wasm-pack --locked; the published wasm-pack crate includes the required lockfile. General CI workflows are outside this change; the revised commit has fresh CI runs.

No live ESRP publication or production hotfix run was performed.

✅ Checklist

General

  • I have included a change request file using $ npm run change
  • I have added tests for my changes.
  • I have tested my changes.
  • I have updated the project documentation to reflect my changes.
  • I have read the CONTRIBUTING documentation and followed the standards for this project.

Agents

  • I have linked to an existing issue in this project that this change addresses
  • I have read the skills
  • I have read the DESIGN.md file(s) in packages relevant to my changes
  • I have updated the DESIGN.md file(s) in packages relevant to my changes

⏭ Next Steps

Merge the prerequisite shared-template update first. After this PR merges, an administrator must complete the activation/permissions steps in build/README.md, validate the pipeline through Azure preview against the merged template, and review the built artifact before approving the first publication. Every queued new valid run requests publishing, subject to the configured approvals; there is no dry-run parameter. Keep all hotfix source tags immutable and outside the GitHub Releases flow.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3d5933b7-14a8-40a3-8140-6992e94efbc8
Comment thread build/scripts/hotfix-registry.mjs Fixed
Comment thread build/scripts/hotfix-registry.mjs Fixed
Comment thread build/scripts/hotfix-release.spec.mjs Fixed
Jane Chu (janechu) and others added 5 commits October 16, 2026 10:56
Require unused npm and crate versions instead of reconciling partial publication. Remove pending-asset copies and self-hashed tooling, preserve provenance and verified completion gates, and encode scoped registry URL components completely.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3d5933b7-14a8-40a3-8140-6992e94efbc8
Remove the publish parameter and opt-in environment flag while preserving manual-main enforcement and publishing approvals. Document how a hotfix tag selects a reviewed commit from a source branch and verify that later branch commits do not change the build.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3d5933b7-14a8-40a3-8140-6992e94efbc8
Keep pipeline tooling central while selecting, validating, and pinning the pushed non-main source branch. Document the branch-from-tag workflow in the agent entry points and publishing guides.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3d5933b7-14a8-40a3-8140-6992e94efbc8
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3d5933b7-14a8-40a3-8140-6992e94efbc8
Delegate npm and Rust publication to the existing publisher with an explicit maintenance channel and strict errors. Retain provenance and registry verification, remove duplicate ESRP inputs, and document the prerequisite template update and three required variables.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3d5933b7-14a8-40a3-8140-6992e94efbc8

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants