Release strategy - #6638
Conversation
…#6607) * ci(release): split gen1/gen2 changesets and publish workflows Splits the shared publish pipeline into independent gen1 (main -> next/latest) and gen2 (gen2-beta -> beta, pre-release mode) release streams per SWC-2315, each with its own changeset folder so a version bump for one generation no longer forces a decision about the other. Introduces a fine-grained bot PAT (RELEASE_BOT_TOKEN, to be added as a repo secret + branch-protection bypass actor) for the version-bump push, replacing the default GITHUB_TOKEN. Adds a release-branch-lock composite action that temporarily blocks PR merges to the target branch for the duration of a real release run, closing the window where a concurrent merge could land between this job's checkout and its final push-back. * ci(release): fully separate changesets per generation Moves from a root-level .changeset + .changeset-2nd-gen split (which needed a copy-into-.changeset shim at release time, since @changesets/cli only ever reads .changeset/ relative to wherever it's invoked) to two genuinely independent changesets instances: 1st-gen/.changeset/ and 2nd-gen/.changeset/, each with its own config.json, README, and now its own @changesets/cli devDependency so `yarn changeset` resolves correctly from within either directory. Removes the runtime copy-in/copy-out step from publish-2nd-gen.yml entirely - it's no longer needed. Also fixes every other repo-root reference to the old single .changeset/ path that would have silently broken or degraded (lint-staged, the 1st-gen changelog/test-changed scripts, the CircleCI docs-only-change filter, and two doc links), since 1st-gen's own nested `workspaces` field means changesets invoked there can no longer see out-of-scope packages by design - those ignore/fixed entries are dropped as dead weight rather than kept as unusable safety nets. * ci(release): make snapshot-release path fully independent per gen publish.yml no longer touches 2nd-gen at all, even for snapshot-release PRs - it never reads 2nd-gen/.changeset/ and has no 2nd-gen version/publish steps. publish-2nd-gen.yml gets its own pull_request (labeled/synchronize, gated to snapshot-release) trigger and handles its own snapshot testing independently: checks out the PR's own head ref, versions with --snapshot snapshot-test (never touching the persistent pre-release state), publishes under snapshot-test, and skips the branch lock and gen2-beta commit/push entirely since a PR run never touches gen2-beta. * fix(ci): use dedicated status-check endpoint for release-branch-lock Replace the read-whole-protection-object-then-PUT-it-back approach with GitHub's dedicated add/remove-contexts endpoints (POST|DELETE .../protection/required_status_checks/contexts). The prior PUT only round-tripped the fields this script knew about (required_status_checks, enforce_admins, required_pull_request_reviews, restrictions), so any other configured protection setting (allow_force_pushes, required_linear_history, etc.) would silently reset to its API default on every lock and unlock. Also renames action.yaml -> action.yml to match the repo's predominant action/workflow file extension. * chore: update release workflows and documentation for gen1/gen2 split * fix(ci): pin release-branch-lock pre-checkout ref to github.sha @main doesn't have .github/actions/release-branch-lock yet - it only exists on this unmerged branch, so every pre-checkout lock step hard-failed with "Can't find action.yml" (seen in run 30274425726). Pin to ${{ github.sha }} instead, which resolves the action from whatever commit is actually running: works now while testing on this branch, and continues to work after merge. * fix(ci): replace composite-action self-reference with inline gh api call uses: doesn't support any expression context, including github - so pinning to ${{ github.sha }} was invalid syntax, not just a wrong ref (confirmed by the workflow validator: "Unrecognized named-value: 'github'"). And a literal @main reference 404s since this action doesn't exist on main yet. Drop the composite-action self-reference for the pre-checkout lock step entirely and inline the gh api call directly - a raw run: step needs no uses: and no repo checkout, so there's no ref to get wrong. Post-checkout steps (unlock in both workflows, both lock/unlock in release-branch-unlock.yml) keep using the composite action via its local ./path reference, which is fine once checkout has happened. * fix(ci): add missing GITHUB_TOKEN to 2nd-gen version step @changesets/changelog-github (2nd-gen's changelog generator, same as 1st-gen's) needs GITHUB_TOKEN to fetch PR/commit info for changelog entries. publish.yml's equivalent step already sets it; publish-2nd-gen.yml's "Version packages" step didn't, so `yarn changeset version` would fail with "Please create a GitHub personal access token ... and add it as the GITHUB_TOKEN environment variable" - reproduced locally before this fix, confirmed resolved after (2.0.0-beta.2 -> 2.0.0-beta.3, CHANGELOG.md and package.json updated correctly for both 2nd-gen packages). * fix(ci): authenticate 2nd-gen npm verify via NODE_AUTH_TOKEN The Verify NPM authentication step wrote ~/.npmrc, but setup-node sets NPM_CONFIG_USERCONFIG so npm reads its own temp .npmrc instead, which authenticates through ${NODE_AUTH_TOKEN}. That token was never set here, so npm whoami got the placeholder and returned 401. Set NODE_AUTH_TOKEN to ADOBE_BOT_NPM_TOKEN and drop the no-op ~/.npmrc write. * ci(release): publish 2nd-gen from main instead of gen2-beta 2nd-gen now releases from main on its own cadence (still beta tag, changesets pre-release mode). Retarget every gen2-beta reference to main: push trigger, branch lock/unlock, checkout ref, commit/push target, the changeset baseBranch, the force-unlock branch choice, and the changeset README. No gen2-beta branch is involved anymore. * ci(release): split gen2 into next (auto) and beta (manual) streams 2nd-gen now publishes two dist-tags with different mechanics: - push to main -> next: continuous throwaway snapshot (changeset version --snapshot next, publish --tag next). No pre-release mode, no branch lock, nothing committed back to main - a rolling build of main for consumers (e.g. the Photoshop dry-run PR) to pull the latest changes. - workflow_dispatch (main only) -> beta: planned pre-release. Enters changesets pre-release mode (beta.N), locks main, versions + changelog, commits the bump back to main. - pull_request + snapshot-release label -> snapshot-test (unchanged). A manual dispatch is restricted to main (github.ref guard); off-main dispatches are skipped. latest is intentionally not supported yet. * chore: ignore .superpowers/ SDD scratch workspace * ci(release): replace 1st-gen direct push-to-main with a Version PR * ci(release): restore snapshot job steps (manifests, build:confirm, React wrappers) * ci(release): replace 2nd-gen direct push-to-main with a beta Version PR * ci(release): add push trigger to check-changesets condition * fix(ci): add push trigger to check-changesets; snapshot runs alongside release on main * chore(ci): remove release-branch-lock machinery * docs(release): describe the Version PR release flow * docs(release): clarify PR title differences between gen1 and gen2 * ci(release): replace changesets/action PR management with peter-evans/create-pull-request changesets/action derives its Version PR branch name solely from the base branch (changeset-release/<baseBranch>), with no per-generation namespacing. Since publish.yml and publish-2nd-gen.yml both target main, both workflows computed the identical branch changeset-release/main and would silently overwrite each other's Version PR whenever both generations had pending changesets. Keep yarn changeset version/publish directly (unaffected by the bug) and manage each generation's Version PR branch explicitly via peter-evans/create-pull-request@v6: changeset-release/1st-gen and changeset-release/2nd-gen. The release job in each workflow now depends on check-changesets and branches on has_changesets instead of relying on changesets/action's own detection. Also remove .github/scripts/toggle-release-lock.mjs, dead code left over from the removed release-branch-lock action, and update the releasing-swc doc to describe the new per-generation branch scheme. * ci(release): manage Version PR branches directly instead of via changesets/action changesets/action derives its Version PR branch name solely from the base branch (changeset-release/<baseBranch>), with no per-generation namespacing. Since publish.yml and publish-2nd-gen.yml both target main, both workflows computed the identical branch changeset-release/main and would silently overwrite each other's Version PR whenever both generations had pending changesets. Keep yarn changeset version/publish directly (unaffected by the bug) and manage each generation's Version PR branch explicitly via peter-evans/create-pull-request@v6: changeset-release/1st-gen and changeset-release/2nd-gen. The release job in each workflow now depends on check-changesets and branches on has_changesets instead of relying on changesets/action's own detection. Update the releasing-swc doc to describe the new per-generation branch scheme. * ci(release): skip build/publish for gen2 when version already on npm Adds a cheap npm-registry check at the top of the publish step so an ordinary push to main with no pending changesets short-circuits before running install/build/changeset publish, mirroring the git-tag guard already used on the 1st-gen side. * ci(release): address review feedback on PR #6601 - Refresh the lockfile after `yarn changeset version`, before opening the Version PR, so the PR's yarn.lock diff actually reflects the bumped internal dependency pins instead of going stale. - Restrict workflow_dispatch's tag input to type: choice (next, snapshot-test) so a manual dispatch can no longer publish under `latest` outside the reviewed Version PR flow. - Give each workflow its own concurrency group (publish-1st-gen-/ publish-2nd-gen-) instead of sharing one repo-wide key across both files - nothing about the new design needs gen1 and gen2 runs to block each other anymore. - Drop the redundant `token: secrets.GITHUB_TOKEN` input on both peter-evans/create-pull-request steps; it's already the action's default. * docs(release): correct the "continuous next" claim to match the actual gate The snapshot job (and its doc description) claimed next is published on every push to main. It's actually gated on has_changesets, same as the Version PR step, so it only refreshes when a push happens to coincide with a pending changeset. Rewords the workflow comments and the contributor doc to describe that instead of the aspirational behavior. * ci(release): use RELEASE_BOT_TOKEN for the Version PR, not GITHUB_TOKEN A PR/branch created with the default GITHUB_TOKEN doesn't trigger other workflows (GitHub's own loop-prevention), so the Version PR - which rewrites every package's version and the lockfile - was merging without this repo's lint/test/VRT checks ever running on it. RELEASE_BOT_TOKEN carries a distinct identity so those pull_request-triggered workflows fire normally. No bypass-actor grant needed this time - it only ever pushes to the changeset-release/* branches, never to a protected branch. * ci(release): address latest review feedback and drop stale "global" naming - Remove RELEASE_BOT_TOKEN from both peter-evans/create-pull-request steps per review feedback - reverting to the default GITHUB_TOKEN. - Remove the redundant "Build all packages" step from all four jobs (snapshot + release, both generations): .github/actions/setup-job already runs yarn build as its last step, so this was a duplicate build on every single run. - Rename 1st-gen/scripts/update-global-changelog.js to update-changelog.js and drop its dead @spectrum-web-components/core changelog branch: that package was renamed to @adobe/spectrum-wc-core and its changesets live in 2nd-gen/.changeset/, which this script never read - the "global" half of the script was unreachable dead code. Renames the npm script changelog:global to changelog:1st-gen and updates its two callers (publish.yml, scripts/publish.js). * ci(release): address latest review feedback and drop stale "global" naming - Remove RELEASE_BOT_TOKEN from both peter-evans/create-pull-request steps per review feedback - reverting to the default GITHUB_TOKEN. - Remove the redundant "Build all packages" step from all four jobs (snapshot + release, both generations): .github/actions/setup-job already runs yarn build as its last step, so this was a duplicate build on every single run. - Drop update-changelog.js's dead @spectrum-web-components/core changelog branch: that package was renamed to @adobe/spectrum-wc-core and its changesets live in 2nd-gen/.changeset/, which this script never read - the "global" half of the script was unreachable dead code. Renames the npm script changelog:global to changelog:1st-gen and updates its two callers (publish.yml, scripts/publish.js). The previous commit (dc140f5) only landed the bare file rename with no content changes due to a staging mistake - this carries the actual edits. * ci(release): fix missing git identity for tag creation, drop stale unified publish script Set git user.name/user.email before create-git-tag.js runs in the release job's publish step - it was dropped when the direct-push-to-main flow was replaced with the Version PR flow, but create-git-tag.js still runs `git tag -a`, which fails without a configured identity. Left unfixed, the tag never lands and every subsequent push re-runs the non-idempotent React wrapper publish loop. Remove scripts/publish.js and its `publish`/`publish:snapshot` yarn scripts: it still ran `yarn changeset version`/`publish` from the repo root, but the root .changeset/config.json no longer exists now that 1st-gen and 2nd-gen have fully independent changesets instances, and nothing in CI or docs referenced this script. * chore: test * Revert "chore: test" This reverts commit 86a939e. --------- Co-authored-by: pvashish_adobe <pvashish@adobe.com>
|
📚 Branch Preview Links🔍 Gen1 Visual Regression Test ResultsWhen a visual regression test fails (or has previously failed while working on this branch), its results can be found in the following URLs:
Deployed to Azure Blob Storage: If the changes are expected, update the |
Coverage Report for CI Build 33086904203Warning Build has drifted: This PR's base is out of sync with its target branch, so coverage data may include unrelated changes. Coverage remained the same at 96.257%Details
Uncovered ChangesNo uncovered changes found. Coverage RegressionsNo coverage regressions found. Coverage Stats💛 - Coveralls |
…merge validation Adds release-strategy as a temporary push trigger, points the gen1/gen2 Version PRs at the triggering branch instead of hardcoded main, and publishes gen1 under the test dist-tag so real consumers on latest are unaffected while validating the release job end-to-end.
Co-authored-by: blunteshwar <32033946+blunteshwar@users.noreply.github.com>
Co-authored-by: blunteshwar <32033946+blunteshwar@users.noreply.github.com>
This reverts commit fa914e2.
… PR titles, and summaries
Co-authored-by: blunteshwar <32033946+blunteshwar@users.noreply.github.com>
Description
Redesigns the npm publish/release automation into two fully independent pipelines,
publish.yml(gen1) andpublish-2nd-gen.yml(gen2), each with its own concurrency group, changeset folder, Version PR branch, git tag prefix, and npm dist-tags — a gen1 release can never race or collide with a gen2 release.Key behavior:
releasejob): triggered onpushtomain, scoped with apathsfilter (1st-gen/**/2nd-gen/**) so a push touching only one generation doesn't trigger the other's workflow. Versions via changesets, opens/updates a dedicated Version PR (changeset-release/1st-gen/changeset-release/2nd-gen) targeting whichever branch triggered the push, then publishes once that PR merges — gated behind thenpm-publishenvironment's required-reviewer approval.gen1-<version>, gen2 checks for git taggen2-<version>(both generations now tag every real release the same way).snapshotjob): triggered onpush, by adding a per-generationsnapshot-release-gen1/snapshot-release-gen2label to a PR, or manually viaworkflow_dispatch. Publishes a disposable prerelease version under an npm dist-tag (nextby default, orsnapshot-testfrom a labeled PR) without touching git, changelog, or opening any PR.snapshot-release-gen1/snapshot-release-gen2) replace the old sharedsnapshot-releaselabel, so a PR can opt a specific generation into a snapshot without affecting the other.Temporary, to remove before merging to
main(marked withTODO/testing comments in both workflow files):release-strategyin thepushtrigger'sbrancheslist — added to validate the full pipeline on this branch before merging.--snapshot teston the real release'schangeset versioncall, and--tag teston its publish steps — lets the release job run its full real path (Version PR → merge → publish → git tag) without shipping an actuallatest/betaversion while testing.Motivation and context
The previous release workflow shared a single changesets/action call and concurrency group across both generations, which meant a gen1 release and a gen2 release could overwrite each other's Version PR branch or serialize behind each other unnecessarily. This redesign gives each generation its own release lifecycle end-to-end.
Validated with multiple full end-to-end cycles directly on this branch: label-triggered snapshot publishes for both generations, real Version PR open → merge → publish cycles (including reverts when testing surfaced issues), and fixes for real problems found along the way — an expired npm token, a missing
pathsfilter that let a gen1-only push trigger gen2's workflow too, and a git tag left behind by a revert that would have silently blocked the next release's idempotency check.Related issue(s)
Screenshots (if appropriate)
Author's checklist
Reviewer's checklist
patch,minor, ormajorfeaturesManual review test cases
Descriptive Test Statement
Descriptive Test Statement
Device review
Accessibility testing checklist
Required: Complete each applicable item and document your testing steps (replace the placeholders with your component-specific instructions).
Keyboard (required — document steps below) — What to test for: Focus order is logical; Tab reaches the component and all interactive descendants; Enter/Space activate where appropriate; arrow keys work for tabs, menus, sliders, etc.; no focus traps; Escape dismisses when applicable; focus indicator is visible.
Screen reader (required — document steps below) — What to test for: Role and name are announced correctly; state changes (e.g. expanded, selected) are announced; labels and relationships are clear; no unnecessary or duplicate announcements.