diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5ce452fe..885dcd6c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,6 +11,7 @@ on: options: - normal - canary + - from-package debug: description: "Verbose publish logs (needed to see Sigstore HTTP status codes)" required: false @@ -59,6 +60,8 @@ jobs: if [ "${{ github.event.inputs.release_type }}" = "canary" ]; then npm run release-canary -- --yes "$@" + elif [ "${{ github.event.inputs.release_type }}" = "from-package" ]; then + npm run release-from-package -- --yes "$@" else npm run release -- --yes "$@" fi diff --git a/RELEASING.md b/RELEASING.md index 78b05cf1..3a2b3ee5 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -1,6 +1,6 @@ # Releasing -Both releases go through the **Release** workflow +Every release goes through the **Release** workflow (`.github/workflows/release.yml`), dispatched by hand with a release type. It runs the matching script below with `--yes`. @@ -26,3 +26,16 @@ The preid carries a UTC timestamp (`--preid canary-$(date -u +%Y%m%d%H%M%S)`). Every other part of a canary version derives from the commit, so without it a second canary from the same commit regenerates a version already on npm and the publish fails. Keep it if you touch that script. + +## Recovering a partial release + +```bash +npm run release-from-package +``` + +A normal release tags, commits and creates the GitHub releases before it +publishes, so when a publish fails midway the failed packages are tagged but +not on npm, and the next normal release sees nothing to bump for them. This +publishes every package whose `package.json` version is missing from the +registry, and nothing else. In the workflow, it is the `from-package` release +type. diff --git a/package.json b/package.json index ac6c0a6e..b620493f 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,8 @@ "lint": "turbo run lint", "test": "turbo run test", "release": "npm run build && lerna publish --conventional-commits --create-release=github", - "release-canary": "npm run build && lerna publish --canary --force-publish --dist-tag canary --preid canary-$(date -u +%Y%m%d%H%M%S)" + "release-canary": "npm run build && lerna publish --canary --force-publish --dist-tag canary --preid canary-$(date -u +%Y%m%d%H%M%S)", + "release-from-package": "npm run build && lerna publish from-package" }, "engines": { "node": "22" diff --git a/patches/sigstore@4.1.1.patch b/patches/sigstore@4.1.1.patch new file mode 100644 index 00000000..eddcfd84 --- /dev/null +++ b/patches/sigstore@4.1.1.patch @@ -0,0 +1,13 @@ +diff --git a/dist/config.js b/dist/config.js +index 373149fe22fb750faeefba5d20a0e432bb91df14..3e3173d504330cd385d84637e12a95eea9731e52 100644 +--- a/dist/config.js ++++ b/dist/config.js +@@ -102,7 +102,7 @@ function initWitnesses(options) { + witnesses.push(new sign_1.RekorWitness({ + rekorBaseURL: options.rekorURL, + entryType: options.legacyCompatibility ? 'intoto' : 'dsse', +- fetchOnConflict: false, ++ fetchOnConflict: true, + retry: options.retry ?? exports.DEFAULT_RETRY, + timeout: options.timeout ?? exports.DEFAULT_TIMEOUT, + })); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5d7f7b90..ee353b64 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -29,6 +29,9 @@ overrides: '@storybook/test-runner>jest-runner': 30.4.2 '@storybook/test-runner>jest-environment-node': 30.4.1 +patchedDependencies: + sigstore@4.1.1: b8e94bc70d270e8d6c7043b27b20485e7886905eb024e80fc41f45f988e67b0c + importers: .: @@ -14898,7 +14901,7 @@ snapshots: npm-registry-fetch: 19.1.1(supports-color@7.2.0) proc-log: 5.0.0 semver: 7.8.5 - sigstore: 4.1.1(supports-color@7.2.0) + sigstore: 4.1.1(patch_hash=b8e94bc70d270e8d6c7043b27b20485e7886905eb024e80fc41f45f988e67b0c)(supports-color@7.2.0) ssri: 12.0.0 transitivePeerDependencies: - supports-color @@ -15835,7 +15838,7 @@ snapshots: npm-registry-fetch: 19.1.1(supports-color@7.2.0) proc-log: 5.0.0 promise-retry: 2.0.1 - sigstore: 4.1.1(supports-color@7.2.0) + sigstore: 4.1.1(patch_hash=b8e94bc70d270e8d6c7043b27b20485e7886905eb024e80fc41f45f988e67b0c)(supports-color@7.2.0) ssri: 12.0.0 tar: 7.5.22 transitivePeerDependencies: @@ -15857,7 +15860,7 @@ snapshots: npm-pick-manifest: 11.0.3 npm-registry-fetch: 19.1.1(supports-color@7.2.0) proc-log: 6.1.0 - sigstore: 4.1.1(supports-color@7.2.0) + sigstore: 4.1.1(patch_hash=b8e94bc70d270e8d6c7043b27b20485e7886905eb024e80fc41f45f988e67b0c)(supports-color@7.2.0) ssri: 13.0.1 tar: 7.5.22 transitivePeerDependencies: @@ -16525,7 +16528,7 @@ snapshots: signal-exit@4.1.0: {} - sigstore@4.1.1(supports-color@7.2.0): + sigstore@4.1.1(patch_hash=b8e94bc70d270e8d6c7043b27b20485e7886905eb024e80fc41f45f988e67b0c)(supports-color@7.2.0): dependencies: '@sigstore/bundle': 4.0.0 '@sigstore/core': 3.2.1 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 1768095c..3195c3b0 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -46,3 +46,12 @@ overrides: minimumReleaseAge: 1440 minimumReleaseAgeExclude: - "@argos-ci/*" + +patchedDependencies: + # Provenance publishing (lerna -> libnpmpublish -> sigstore). When a Rekor + # write commits but the 5s client timeout fires first, sigstore retries and + # Rekor answers 409 "an equivalent entry already exists". sigstore hardcodes + # `fetchOnConflict: false`, so that 409 kills the publish mid-release. The + # patch turns it on: on a 409, fetch the entry we already wrote and carry on. + # Drop once https://github.com/sigstore/sigstore-js/issues/1708 is fixed. + sigstore@4.1.1: patches/sigstore@4.1.1.patch