Skip to content

ci(release): per-package ADO release stages + build on Node 22 - #336

Merged
YunchuWang merged 2 commits into
mainfrom
ado-release-per-package-stages
Jul 29, 2026
Merged

ci(release): per-package ADO release stages + build on Node 22#336
YunchuWang merged 2 commits into
mainfrom
ado-release-per-package-stages

Conversation

@YunchuWang

Copy link
Copy Markdown
Member

Summary

Restructures the 1ES Official ADO release pipeline so the three npm packages in this monorepo can be released independently and in the required order, and bumps the official build to the Node version the packages actually require. Two independent fixes, two files.

B13 — per-package release stages (eng/ci/release.yml)

All three ESRP publish jobs previously lived under a single - stage: release. In Azure DevOps, only stages are individually selectable at queue time (the "Stages to run" picker) — jobs are not. So queuing the release published all three packages at once.

That breaks this repo's release, because the packages ship at different versions with a hard ordering constraint:

package npm name version dist-tag
packages/durabletask-js @microsoft/durabletask-js 0.4.0 latest
packages/durabletask-js-azuremanaged @microsoft/durabletask-js-azuremanaged 0.4.0 latest
packages/azure-functions-durable durable-functions 4.0.0-beta.1 preview

packages/azure-functions-durable/package.json pins "@microsoft/durabletask-js": "0.4.0" exactly, so core must be on npm before the compat package. Publishing them together (or compat first) puts an uninstallable package on the registry.

Fix: split the single stage into three, one job each, mirroring durabletask-python's already-shipped layout:

  • release_durabletask_js — core; no dependency
  • release_durabletask_js_azuremanageddependsOn: release_durabletask_js
  • release_durable_functionsdependsOn: release_durabletask_js

Both dependents depend on core only, not on each other (siblings, not a serial chain). Because ADO skips a de-selected stage at queue time, the operator can release core alone now and a dependent later — the dependent stage then runs on its own.

This is a pure structural refactor: every EsrpRelease@9 input and each job's templateContext is preserved byte-for-byte (the three ESRP input blocks and the three templateContext blocks hash-identical to origin/main). No environment:, condition:, or new ESRP input was added.

B12 — official build runs the supported Node (eng/templates/build.yml)

The build that produces the shipped .tgz artifacts installed Node via NodeTool@0 versionSpec: 20.x, but all packages declare "engines": { "node": ">=22.0.0" } and GitHub CI only tests 22.x/24.x. So the runtime that builds the released artifacts was never covered by the green CI signal and ran a Node the packages call unsupported. Changed 20.x22.x (the version CI already exercises). This is the only Node-version reference in eng/.

Out of scope

  • No package versions or packages/** changes.
  • Does not touch .github/workflows/prepare-release.yaml (that is a separate PR).
  • Pipelines are not queued or run as part of this PR.

B13: eng/ci/release.yml published all three npm packages from a single
`- stage: release`. In Azure DevOps only STAGES are individually selectable at
queue time ("Stages to run") -- jobs are not -- so queuing a release published
core, azuremanaged and durable-functions together. durable-functions pins
"@microsoft/durabletask-js" to an EXACT version, so core must reach the registry
first; a combined publish would put an uninstallable compat package on npm.

Split the single stage into three, one job each, mirroring durabletask-python:
- release_durabletask_js (core; no dependency)
- release_durabletask_js_azuremanaged (dependsOn: release_durabletask_js)
- release_durable_functions           (dependsOn: release_durabletask_js)
The two dependents depend on CORE only, not on each other (siblings, not chained).
Because ADO skips a de-selected stage at queue time, core can be released on its own
and a dependent released later. Every EsrpRelease@9 input and each job's
templateContext are preserved byte-for-byte; no environment/condition/input added.

B12: eng/templates/build.yml built the shipped .tgz artifacts on Node 20
(NodeTool@0 versionSpec: 20.x) while all packages declare engines node >=22.0.0 and
GitHub CI only tests 22.x/24.x -- so the runtime that builds the released artifacts
was never covered by the green CI signal and ran a Node the packages call
unsupported. Bump the official build to 22.x, the conservative choice already
exercised by CI. No other change to that file.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d86f5f69-4e1a-4c1d-b017-5e290c85cc05
Copilot AI review requested due to automatic review settings July 29, 2026 22:02

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Updates the Azure DevOps (1ES Official) pipeline definitions to (1) support per-package releases in this monorepo via individually selectable stages and (2) align the official build’s Node.js version with the packages’ declared engine requirements.

Changes:

  • Split the single ADO release stage into three per-package stages with ordering constraints via dependsOn.
  • Update the official build template to install Node.js 22.x instead of 20.x.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
eng/ci/release.yml Refactors the release pipeline into three independently selectable stages and adds stage dependencies to enforce publish ordering.
eng/templates/build.yml Bumps the NodeTool installation from 20.x to 22.x for the official build.
Comments suppressed due to low confidence (1)

eng/ci/release.yml:106

  • Same issue as the other dependent stage: with dependsOn: release_durabletask_js, this stage will be skipped if the core stage is de-selected at queue time. If the goal is to allow releasing this package independently after core is already published, add a condition that permits running when the dependency stage was skipped.
      # Publish the core durabletask-js stage before this dependent package: durable-functions
      # pins "@microsoft/durabletask-js" to an EXACT version, so core must be on the registry
      # first or the published package is uninstallable. This depends on the core stage only,
      # not on the azuremanaged stage (they are siblings, mirroring durabletask-python). If the
      # core stage is de-selected at queue time, ADO skips it and this stage runs on its own.
      dependsOn: release_durabletask_js
      jobs:

Comment thread eng/ci/release.yml
…cted

The Copilot PR reviewer flagged that with `dependsOn: release_durabletask_js`
alone, ADO's DEFAULT stage condition requires the core stage to have completed
and succeeded, so de-selecting the core stage at queue time (to release only a
dependent package) would SKIP the dependent stage too. That contradicts the
adjacent comment claiming the stage "runs on its own": the comment copied from
durabletask-python is wrong -- verified against Microsoft Learn, ADO does not
run a stage whose dependency was Skipped unless an explicit condition allows it.

Add an explicit stage-level condition to BOTH dependent stages:
  condition: in(dependencies.release_durabletask_js.result, 'Succeeded', 'SucceededWithIssues', 'Skipped')

This accepts a Skipped core stage (enabling independent release when core is
de-selected) while still rejecting Failed and Canceled, so a real core publish
FAILURE still blocks the dependent stages. That matters most for durable-functions,
whose exact pin "@microsoft/durabletask-js": "0.4.0" would otherwise ship an
uninstallable package if core failed. The fix is strictly safe: if de-selection
already worked the condition changes nothing; if it did not, it fixes it.

The core stage keeps ADO's default (no dependsOn, no condition). Both stage
comments are corrected to describe the real behavior. Only eng/ci/release.yml
changes; ESRP inputs and templateContext blocks are byte-identical to d00b502.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d86f5f69-4e1a-4c1d-b017-5e290c85cc05
Copilot AI review requested due to automatic review settings July 29, 2026 22:21

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

@YunchuWang
YunchuWang merged commit 3ebaf33 into main Jul 29, 2026
17 checks passed
@YunchuWang
YunchuWang deleted the ado-release-per-package-stages branch July 29, 2026 22:30
YunchuWang added a commit that referenced this pull request Jul 29, 2026
doc/release_process.md is the runbook Bill will follow for this release, but
it still described the old "all packages share one version, publish manually"
model and, followed as written, would produce a wrong release. Update it to
match the per-package release tooling (PR #335 prepare-release workflow +
PR #336 ADO per-package stages).

- Scope: cover all three published packages -- @microsoft/durabletask-js
  (core), @microsoft/durabletask-js-azuremanaged, and durable-functions
  (source dir packages/azure-functions-durable) -- in the intro, Overview
  table, the Step 2 .tgz list, and the Step 4 npm-view list.
- Versioning Policy: replace "all packages same version" with per-package
  independent versioning/changelog/tags; document the one hard ordering
  constraint (compat exact-pins core, so core must publish first or the
  published compat package is uninstallable) and that azuremanaged is
  unordered (peer floor >=0.3.0 already satisfied by published core).
- Resolve the self-contradiction: ESRP via eng/ci/release.yml is the
  sanctioned publish path; a manual npm publish is the alternative.
- Prepare Release section: document the required `package` input and that the
  workflow bumps only the selected package and writes only that package's own
  changelog file (root CHANGELOG.md for core/azuremanaged,
  packages/azure-functions-durable/CHANGELOG.md for durable-functions).
- Branch/tag naming: prefix-derived (v / azuremanaged-v / durable-functions-v)
  with concrete examples, in the workflow section, Step 2, Step 5, and the
  manual steps.
- Step 3: three ADO stages (not jobs), individually selectable at queue time,
  core-before-compat ordering, and the explicit Skipped-accepting condition
  (rejects Failed/Canceled) added in PR #336.
- Manual section: bump only the released package; add the durable-functions
  exact-pin dependency step.
- Dist tags: reconcile the general semver table with the tooling (every
  prerelease -> preview) and make durable-functions@preview explicit
  (cross-checked against packages/azure-functions-durable/CHANGELOG.md).
- Flag B11 (whether ESRP can set an npm dist-tag) as an explicit open
  question, not fact.

Docs only; no code or behavior change.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d86f5f69-4e1a-4c1d-b017-5e290c85cc05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants