Publish from one workflow, with a job per registry - #711
Open
TemplarGeneral wants to merge 1 commit into
Open
Conversation
No stable release had ever published. tag-release.yml set top-level `permissions: contents: read` and its calling job set none of its own, so the reusable release.yml was capped at read while its publish job asked for `contents: write`. A called workflow may only narrow the caller's token, so GitHub rejected the graph before any job started -- every Tag release run since the workflow landed ended in startup_failure inside a second. Nothing had reached Open VSX either, on either channel. The release path never ran at all. On the pre-release path the Marketplace step ran first in the same job and timed out on /_apis/gallery pushing all six platform VSIX files through one `vsce publish` call; a failed step aborts the job, so the Open VSX step below it never executed. The namespace has been sitting empty since it was created. Both are the same structural fault -- three workflows racing on one push, with all three publish targets as sequential steps in a single job -- so replace pre-release.yml, release.yml and tag-release.yml with one publish.yml: * `check` picks the channel once. A commit whose manifest matches the top changelog heading with no tag for it yet is a release; everything else is a pre-release. A release commit no longer also publishes a pre-release, so the five-platform Rust matrix runs once per push instead of twice. * `verify` fails the run before the 45-minute matrix when a release is missing a publish token, and now checks OPEN_VSX_TOKEN as well as VSCE_TOKEN. A release skipping Open VSX in silence is half of why this went unnoticed. * Marketplace, Open VSX and GitHub Releases each publish as their own job, in parallel, from one packaged artifact. A failure names itself in the Actions UI, one registry can no longer cancel another, and re-running a single red job re-publishes a single target. * The tag is created by the GitHub job rather than ahead of the build, so a tag means published, not attempted -- and a release that failed to publish is retried by the next push to main. * `release-failed` opens a draft fix/release-v<x.y.z> pull request listing the jobs that broke with links to their logs. There is no reusable-workflow call left anywhere, and a test asserts there is none, so the permission ceiling cannot come back. publish_to_marketplace now uploads one VSIX per `vsce publish` call with --skip-duplicate, retrying each three times with a backoff and collecting failures rather than stopping at the first, so a flaky gallery upload cannot strand the other five platforms and a re-run only retries what is missing. publish-marketplace.yml gets the same treatment. The GitHub release half splits out as `publish-github`, which generates pre-release notes instead of demanding a CHANGELOG section and passes --target so it can tag from a branch ref -- that is what lets one job serve both channels. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Contributor
Coverage
🟢 ≥80% · 🟡 ≥50% · 🔴 <50% · ⚪ unavailable. Expand a section for file coverage and the full-report artifact. Rust engine details: 20 worst-covered files of 136
Full report is in the Extension-host client details: 7 filesMeasured labels:
Full report is in the Node unit details: 19 files
Full report is in the |
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.
Two confirmed bugs, one structural cause, one replacement workflow.
What was broken
No stable release had ever published. Every
Tag releaserun ended instartup_failureinside a second — runs 34244103258, 34244162650, 34266213493, 34266444443, which is every run since the workflow landed.tag-release.ymlset top-levelpermissions: contents: readand itsrelease:calling job set none of its own, so the reusablerelease.ymlwas capped at read while itspublishjob asked forcontents: write. A called workflow may only narrow the caller's token, so GitHub rejected the whole graph before any job started.Nothing had reached Open VSX, on either channel.
open-vsx.org/api/milleniumdawnmodteamreturns{"extensions":{}}— the namespace exists and is empty, so nothing needed creating. The release path never ran (above). On the pre-release path the Marketplace step ran first in the same job and timed out on/_apis/gallerypushing all six platform VSIX files through onevsce publishcall; a failed step aborts the job, so the Open VSX step below it never executed. Both pre-release runs ever attempted died exactly this way.Both are the same structural fault: three workflows racing on one push, with all three publish targets as sequential steps in a single job.
What replaces it
pre-release.yml,release.ymlandtag-release.ymlbecome onepublish.yml:checkpicks the channel once and everything downstream reads it. A release commit no longer also publishes a pre-release, so the five-platform Rust matrix runs once per push instead of twice.verifyfails before the 45-minute matrix when a release is missing a publish token — and now checksOPEN_VSX_TOKEN, not justVSCE_TOKEN. A release skipping Open VSX in silence is half of why this went unnoticed.--skip-duplicateon both registries makes that safe).main.release-failedopens a draftfix/release-v<x.y.z>PR listing the jobs that broke with links to their logs, using the same GitHub App asrelease-pr.yml.There is no reusable-workflow call left anywhere, and
tests/scripts/test_publish_workflow.pyasserts there is none, so the permission ceiling cannot come back.Marketplace robustness
publish_to_marketplacenow uploads one VSIX pervsce publishcall with--skip-duplicate, retries each three times with a 15s/45s backoff, and collects failures instead of stopping at the first — a flaky gallery upload can no longer strand the other five platforms, and a re-run only retries what is missing.publish-marketplace.ymlgets the same treatment. The GitHub half splits out aspublish-github, which generates pre-release notes rather than demanding a CHANGELOG section and passes--targetso it can tag from a branch ref; that is what lets one job serve both channels.Verification
actionlintv1.7.7: 0 errors in 7 files, including the newpublish.yml.pytest(269 tests),ruff,black --check,mypy,pylint,npm run check— all clean. Two pre-existing Windows-only local failures (test_esbuildWinError 193,pylintonsignal.SIGKILL) are untouched by this change and green on Linux CI.checkjob's shell was run against this tree: it correctly resolvesmanifest=3.4.1 changelog=3.4.1, nov3.4.1tag → release, andprerelease-identity→3.5.42/v3.5.42-pre.1on the other branch.Heads-up on merging
extension/package/package.jsonis at 3.4.1, the top changelog heading is 3.4.1, and nov3.4.1tag exists — becausetag-release.ymlnever worked. So the merge commit will be read as a release commit and this PR's own push tomainwill publish v3.4.1 to the Marketplace, Open VSX and GitHub Releases. That is the intended catch-up, but it means the first run is a real release rather than a pre-release. The changelog bullet for this change sits under### Unreleased, sorelease-pr.ymlwill follow with a 3.4.2 PR.Risks worth knowing
--skip-duplicatemeans a fix that changes shipped code must bump the version — a registry that already accepted the version silently keeps the broken upload. The fix-PR body says so.mainre-attempts it, so the pre-release channel pauses until it lands.Publish: GitHubsucceeds and only a registry fails, the tag exists, socheckwill not retry: re-run that one job or dispatchpublish-marketplace.yml. Documented in CONTRIBUTING.🤖 Generated with Claude Code