Repository navigation
Release #9
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
| name: Release | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: 'Canonical npm version without the v prefix' | |
| required: true | |
| type: string | |
| commit_sha: | |
| description: 'Full 40-character lowercase SHA of the current main commit' | |
| required: true | |
| type: string | |
| batch_id: | |
| description: '1-64 characters; start with a letter or digit; use only letters, digits, ., _, or -' | |
| required: true | |
| type: string | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: release | |
| cancel-in-progress: false | |
| env: | |
| NODE_VERSION: '22.x' | |
| NPM_REGISTRY: 'https://registry.npmjs.org' | |
| PACKAGE_NAME: 'qca-sdk' | |
| jobs: | |
| preflight: | |
| runs-on: ubuntu-latest | |
| env: | |
| RELEASE_VERSION: ${{ inputs.version }} | |
| RELEASE_COMMIT_SHA: ${{ inputs.commit_sha }} | |
| RELEASE_BATCH_ID: ${{ inputs.batch_id }} | |
| outputs: | |
| artifact_name: ${{ steps.pack.outputs.artifact_name }} | |
| tarball_name: ${{ steps.pack.outputs.tarball_name }} | |
| tarball_sha256: ${{ steps.pack.outputs.tarball_sha256 }} | |
| dist_tag: ${{ steps.release-meta.outputs.dist_tag }} | |
| steps: | |
| - name: Validate dispatch metadata | |
| run: | | |
| set -euo pipefail | |
| if [[ "$GITHUB_REF" != 'refs/heads/main' || "$GITHUB_WORKFLOW_REF" != *@refs/heads/main ]]; then | |
| echo 'Releases must be dispatched from the main workflow ref.' >&2 | |
| exit 1 | |
| fi | |
| if [[ ! "$RELEASE_COMMIT_SHA" =~ ^[0-9a-f]{40}$ ]]; then | |
| echo 'commit_sha must be a full 40-character lowercase Git SHA.' >&2 | |
| exit 1 | |
| fi | |
| if [[ ! "$RELEASE_BATCH_ID" =~ ^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$ ]]; then | |
| echo 'batch_id must be 1-64 safe audit-token characters.' >&2 | |
| exit 1 | |
| fi | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 | |
| with: | |
| ref: ${{ inputs.commit_sha }} | |
| fetch-depth: 0 | |
| - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| cache: npm | |
| registry-url: ${{ env.NPM_REGISTRY }} | |
| - name: Use trusted-publishing npm version | |
| run: npm install --global npm@12.0.0 | |
| - name: Validate release version and commit | |
| run: | | |
| set -euo pipefail | |
| git fetch --force --prune --prune-tags origin \ | |
| '+refs/heads/main:refs/remotes/origin/main' \ | |
| '+refs/tags/*:refs/tags/*' | |
| checked_out_sha=$(git rev-parse 'HEAD^{commit}') | |
| requested_sha=$(git rev-parse "$RELEASE_COMMIT_SHA^{commit}") | |
| main_sha=$(git rev-parse 'refs/remotes/origin/main^{commit}') | |
| tag_sha=$(git rev-parse -q --verify "refs/tags/v$RELEASE_VERSION^{commit}" || true) | |
| if [[ "$checked_out_sha" != "$requested_sha" ]]; then | |
| echo "Checked out $checked_out_sha instead of requested $requested_sha." >&2 | |
| exit 1 | |
| fi | |
| if [[ "$requested_sha" != "$main_sha" && "$tag_sha" != "$requested_sha" ]]; then | |
| echo "commit_sha is neither current origin/main ($main_sha) nor an existing matching release tag." >&2 | |
| exit 1 | |
| fi | |
| version_dir=$(mktemp -d) | |
| trap 'rm -rf "$version_dir"' EXIT | |
| printf '%s\n' '{"name":"release-version-check","version":"0.0.0","private":true}' > "$version_dir/package.json" | |
| npm --prefix "$version_dir" version "$RELEASE_VERSION" \ | |
| --no-git-tag-version --allow-same-version >/dev/null | |
| canonical_version=$(node -p "require(process.argv[1]).version" "$version_dir/package.json") | |
| if [[ "$canonical_version" != "$RELEASE_VERSION" ]]; then | |
| echo 'version must be a canonical npm semver without a v prefix.' >&2 | |
| exit 1 | |
| fi | |
| rm -rf "$version_dir" | |
| trap - EXIT | |
| node <<'NODE' | |
| const { readFileSync } = require('node:fs'); | |
| const expected = process.env.RELEASE_VERSION; | |
| const packageJson = JSON.parse(readFileSync('package.json', 'utf8')); | |
| const packageLock = JSON.parse(readFileSync('package-lock.json', 'utf8')); | |
| const source = readFileSync('src/version.ts', 'utf8'); | |
| const matches = [...source.matchAll(/^export const VERSION = '([^']+)';$/gm)]; | |
| const versions = { | |
| 'package.json': packageJson.version, | |
| 'package-lock.json': packageLock.version, | |
| 'package-lock.json root package': packageLock.packages?.['']?.version, | |
| 'src/version.ts': matches.length === 1 ? matches[0][1] : undefined, | |
| }; | |
| for (const [file, version] of Object.entries(versions)) { | |
| if (version !== expected) { | |
| throw new Error(`${file} version ${String(version)} does not match ${expected}`); | |
| } | |
| } | |
| NODE | |
| - name: Validate and preview release notes | |
| env: | |
| RELEASE_VERSION: ${{ inputs.version }} | |
| run: | | |
| set -euo pipefail | |
| python3 .github/scripts/release_notes.py extract \ | |
| --version "$RELEASE_VERSION" --output "$RUNNER_TEMP/release-notes.md" | |
| echo "## Changelog for v$RELEASE_VERSION" >> "$GITHUB_STEP_SUMMARY" | |
| cat "$RUNNER_TEMP/release-notes.md" >> "$GITHUB_STEP_SUMMARY" | |
| - id: state | |
| name: Inspect tag and registry state | |
| run: | | |
| set -euo pipefail | |
| release_sha=$(git rev-parse "$RELEASE_COMMIT_SHA^{commit}") | |
| tag="v$RELEASE_VERSION" | |
| tag_sha=$(git rev-parse -q --verify "refs/tags/$tag^{commit}" || true) | |
| if [[ -n "$tag_sha" ]]; then | |
| if [[ "$tag_sha" != "$release_sha" ]]; then | |
| echo "$tag already points to $tag_sha, not $release_sha." >&2 | |
| exit 1 | |
| fi | |
| if [[ "$(git cat-file -t "refs/tags/$tag")" != tag ]]; then | |
| echo "$tag must be an annotated release tag." >&2 | |
| exit 1 | |
| fi | |
| tag_message=$(git for-each-ref --format='%(contents)' "refs/tags/$tag") | |
| if [[ "$tag_message" != "Release $PACKAGE_NAME@$RELEASE_VERSION (batch $RELEASE_BATCH_ID)" ]]; then | |
| echo "$tag does not have the expected release annotation." >&2 | |
| exit 1 | |
| fi | |
| fi | |
| tag_exists=false | |
| [[ -n "$tag_sha" ]] && tag_exists=true | |
| error_file=$(mktemp) | |
| if registry_version=$(npm view "$PACKAGE_NAME@$RELEASE_VERSION" version \ | |
| --registry "$NPM_REGISTRY" 2>"$error_file"); then | |
| if [[ "$registry_version" != "$RELEASE_VERSION" ]]; then | |
| echo "Registry returned unexpected version: $registry_version" >&2 | |
| exit 1 | |
| fi | |
| registry_exists=true | |
| elif grep -q 'E404' "$error_file"; then | |
| registry_exists=false | |
| else | |
| echo 'Unable to query the public npm registry:' >&2 | |
| cat "$error_file" >&2 | |
| exit 1 | |
| fi | |
| rm -f "$error_file" | |
| if [[ "$registry_exists" == true && "$tag_exists" == false ]]; then | |
| echo "$PACKAGE_NAME@$RELEASE_VERSION exists without matching tag $tag." >&2 | |
| exit 1 | |
| fi | |
| echo "tag_exists=$tag_exists" >> "$GITHUB_OUTPUT" | |
| echo "registry_exists=$registry_exists" >> "$GITHUB_OUTPUT" | |
| - run: npm ci | |
| - id: release-meta | |
| name: Select and validate npm dist-tag | |
| env: | |
| REGISTRY_EXISTS: ${{ steps.state.outputs.registry_exists }} | |
| run: | | |
| set -euo pipefail | |
| dist_tag=$(node -e "const semver=require('semver'); process.stdout.write(semver.prerelease(process.env.RELEASE_VERSION) ? 'next' : 'latest')") | |
| if [[ "$REGISTRY_EXISTS" == false ]]; then | |
| current=$(npm view "$PACKAGE_NAME" "dist-tags.$dist_tag" --registry "$NPM_REGISTRY") | |
| if [[ -n "$current" ]]; then | |
| DIST_TAG="$dist_tag" node -e "const semver=require('semver'); if (!semver.gt(process.env.RELEASE_VERSION, process.argv[1])) { throw new Error(process.env.RELEASE_VERSION + ' must be newer than current ' + process.env.DIST_TAG + ' ' + process.argv[1]); }" "$current" | |
| fi | |
| fi | |
| echo "dist_tag=$dist_tag" >> "$GITHUB_OUTPUT" | |
| - run: npm run build | |
| - run: npm run typecheck | |
| - run: npm test | |
| - run: npm run docs:check | |
| - id: pack | |
| name: Pack release artifact | |
| run: | | |
| set -euo pipefail | |
| tarball_name=$(npm pack --silent) | |
| expected_name="$PACKAGE_NAME-$RELEASE_VERSION.tgz" | |
| if [[ "$tarball_name" != "$expected_name" || ! -f "$tarball_name" ]]; then | |
| echo "npm pack produced unexpected artifact: $tarball_name" >&2 | |
| exit 1 | |
| fi | |
| tarball_sha256=$(sha256sum "$tarball_name" | cut -d ' ' -f 1) | |
| echo "artifact_name=$PACKAGE_NAME-$RELEASE_VERSION" >> "$GITHUB_OUTPUT" | |
| echo "tarball_name=$tarball_name" >> "$GITHUB_OUTPUT" | |
| echo "tarball_sha256=$tarball_sha256" >> "$GITHUB_OUTPUT" | |
| - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 | |
| with: | |
| name: ${{ steps.pack.outputs.artifact_name }} | |
| path: ${{ steps.pack.outputs.tarball_name }} | |
| if-no-files-found: error | |
| retention-days: 7 | |
| publish: | |
| needs: preflight | |
| runs-on: ubuntu-latest | |
| outputs: | |
| registry_existed: ${{ steps.state.outputs.registry_exists }} | |
| environment: release | |
| permissions: | |
| contents: write | |
| id-token: write | |
| env: | |
| RELEASE_VERSION: ${{ inputs.version }} | |
| RELEASE_COMMIT_SHA: ${{ inputs.commit_sha }} | |
| RELEASE_BATCH_ID: ${{ inputs.batch_id }} | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 | |
| with: | |
| ref: ${{ inputs.commit_sha }} | |
| fetch-depth: 0 | |
| - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 | |
| with: | |
| name: ${{ needs.preflight.outputs.artifact_name }} | |
| path: release-artifact | |
| - id: artifact | |
| name: Verify downloaded artifact | |
| env: | |
| TARBALL_NAME: ${{ needs.preflight.outputs.tarball_name }} | |
| TARBALL_SHA256: ${{ needs.preflight.outputs.tarball_sha256 }} | |
| run: | | |
| set -euo pipefail | |
| tarball_path="$GITHUB_WORKSPACE/release-artifact/$TARBALL_NAME" | |
| if [[ ! -f "$tarball_path" ]]; then | |
| echo "Downloaded artifact is missing $TARBALL_NAME." >&2 | |
| exit 1 | |
| fi | |
| actual_sha256=$(sha256sum "$tarball_path" | cut -d ' ' -f 1) | |
| if [[ "$actual_sha256" != "$TARBALL_SHA256" ]]; then | |
| echo 'Downloaded artifact checksum does not match preflight.' >&2 | |
| exit 1 | |
| fi | |
| echo "tarball_path=$tarball_path" >> "$GITHUB_OUTPUT" | |
| - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| registry-url: ${{ env.NPM_REGISTRY }} | |
| - name: Use trusted-publishing npm version | |
| run: npm install --global npm@12.0.0 | |
| - id: state | |
| name: Revalidate main, tag, and registry | |
| run: | | |
| set -euo pipefail | |
| git fetch --force --prune --prune-tags origin \ | |
| '+refs/heads/main:refs/remotes/origin/main' \ | |
| '+refs/tags/*:refs/tags/*' | |
| checked_out_sha=$(git rev-parse 'HEAD^{commit}') | |
| release_sha=$(git rev-parse "$RELEASE_COMMIT_SHA^{commit}") | |
| main_sha=$(git rev-parse 'refs/remotes/origin/main^{commit}') | |
| tag="v$RELEASE_VERSION" | |
| tag_sha=$(git rev-parse -q --verify "refs/tags/$tag^{commit}" || true) | |
| if [[ "$checked_out_sha" != "$release_sha" ]]; then | |
| echo "Checked out $checked_out_sha instead of requested $release_sha." >&2 | |
| exit 1 | |
| fi | |
| if [[ "$main_sha" != "$release_sha" && "$tag_sha" != "$release_sha" ]]; then | |
| echo "origin/main moved to $main_sha before the release tag was created; dispatch a new release." >&2 | |
| exit 1 | |
| fi | |
| if [[ -n "$tag_sha" ]]; then | |
| if [[ "$tag_sha" != "$release_sha" ]]; then | |
| echo "$tag now points to $tag_sha, not $release_sha." >&2 | |
| exit 1 | |
| fi | |
| if [[ "$(git cat-file -t "refs/tags/$tag")" != tag ]]; then | |
| echo "$tag must be an annotated release tag." >&2 | |
| exit 1 | |
| fi | |
| tag_message=$(git for-each-ref --format='%(contents)' "refs/tags/$tag") | |
| if [[ "$tag_message" != "Release $PACKAGE_NAME@$RELEASE_VERSION (batch $RELEASE_BATCH_ID)" ]]; then | |
| echo "$tag does not have the expected release annotation." >&2 | |
| exit 1 | |
| fi | |
| fi | |
| tag_exists=false | |
| [[ -n "$tag_sha" ]] && tag_exists=true | |
| error_file=$(mktemp) | |
| if registry_version=$(npm view "$PACKAGE_NAME@$RELEASE_VERSION" version \ | |
| --registry "$NPM_REGISTRY" 2>"$error_file"); then | |
| if [[ "$registry_version" != "$RELEASE_VERSION" ]]; then | |
| echo "Registry returned unexpected version: $registry_version" >&2 | |
| exit 1 | |
| fi | |
| registry_exists=true | |
| elif grep -q 'E404' "$error_file"; then | |
| registry_exists=false | |
| else | |
| echo 'Unable to query the public npm registry:' >&2 | |
| cat "$error_file" >&2 | |
| exit 1 | |
| fi | |
| rm -f "$error_file" | |
| if [[ "$registry_exists" == true && "$tag_exists" == false ]]; then | |
| echo "$PACKAGE_NAME@$RELEASE_VERSION exists without matching tag $tag." >&2 | |
| exit 1 | |
| fi | |
| echo "tag_exists=$tag_exists" >> "$GITHUB_OUTPUT" | |
| echo "registry_exists=$registry_exists" >> "$GITHUB_OUTPUT" | |
| - name: Create or reuse release tag | |
| env: | |
| TAG_EXISTS: ${{ steps.state.outputs.tag_exists }} | |
| run: | | |
| set -euo pipefail | |
| tag="v$RELEASE_VERSION" | |
| if [[ "$TAG_EXISTS" == true ]]; then | |
| echo "Reusing $tag at $RELEASE_COMMIT_SHA." | |
| exit 0 | |
| fi | |
| git config user.name 'github-actions[bot]' | |
| git config user.email '41898282+github-actions[bot]@users.noreply.github.com' | |
| git tag --annotate "$tag" "$RELEASE_COMMIT_SHA" \ | |
| --message "Release $PACKAGE_NAME@$RELEASE_VERSION (batch $RELEASE_BATCH_ID)" | |
| git push --atomic --force-with-lease="refs/heads/main:$RELEASE_COMMIT_SHA" origin \ | |
| "${RELEASE_COMMIT_SHA}:refs/heads/main" "refs/tags/$tag" | |
| - name: Publish to npm with trusted publishing | |
| if: steps.state.outputs.registry_exists == 'false' | |
| env: | |
| TARBALL_PATH: ${{ steps.artifact.outputs.tarball_path }} | |
| DIST_TAG: ${{ needs.preflight.outputs.dist_tag }} | |
| run: npm publish "$TARBALL_PATH" --registry "$NPM_REGISTRY" --tag "$DIST_TAG" --access public --provenance | |
| - name: Record publish result | |
| env: | |
| REGISTRY_EXISTS: ${{ steps.state.outputs.registry_exists }} | |
| DIST_TAG: ${{ needs.preflight.outputs.dist_tag }} | |
| run: | | |
| if [[ "$REGISTRY_EXISTS" == true ]]; then | |
| echo "Reused existing $PACKAGE_NAME@$RELEASE_VERSION; npm upload skipped." >> "$GITHUB_STEP_SUMMARY" | |
| else | |
| echo "Published $PACKAGE_NAME@$RELEASE_VERSION under $DIST_TAG." >> "$GITHUB_STEP_SUMMARY" | |
| fi | |
| verify: | |
| needs: [preflight, publish] | |
| runs-on: ubuntu-latest | |
| env: | |
| RELEASE_VERSION: ${{ inputs.version }} | |
| DIST_TAG: ${{ needs.preflight.outputs.dist_tag }} | |
| REGISTRY_EXISTED: ${{ needs.publish.outputs.registry_existed }} | |
| steps: | |
| - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| registry-url: ${{ env.NPM_REGISTRY }} | |
| - name: Use verification npm version | |
| run: npm install --global npm@12.0.0 | |
| - name: Wait for and verify registry artifact | |
| env: | |
| TARBALL_SHA256: ${{ needs.preflight.outputs.tarball_sha256 }} | |
| run: | | |
| set -euo pipefail | |
| error_file=$(mktemp) | |
| for attempt in $(seq 1 20); do | |
| if registry_version=$(npm view "$PACKAGE_NAME@$RELEASE_VERSION" version \ | |
| --registry "$NPM_REGISTRY" 2>"$error_file"); then | |
| if [[ "$registry_version" == "$RELEASE_VERSION" ]]; then | |
| break | |
| fi | |
| echo "Registry returned unexpected version: $registry_version" >&2 | |
| exit 1 | |
| fi | |
| if ! grep -q 'E404' "$error_file"; then | |
| echo 'Unable to query the public npm registry:' >&2 | |
| cat "$error_file" >&2 | |
| exit 1 | |
| fi | |
| if [[ "$attempt" == 20 ]]; then | |
| echo "$PACKAGE_NAME@$RELEASE_VERSION did not become visible after 20 attempts." >&2 | |
| exit 1 | |
| fi | |
| sleep 15 | |
| done | |
| metadata_file=$(mktemp) | |
| npm view "$PACKAGE_NAME@$RELEASE_VERSION" dist --json \ | |
| --registry "$NPM_REGISTRY" > "$metadata_file" | |
| registry_tarball=$(node - "$metadata_file" <<'NODE' | |
| const { readFileSync } = require('node:fs'); | |
| const payload = JSON.parse(readFileSync(process.argv[2], 'utf8')); | |
| const dist = Array.isArray(payload) ? payload[0] : payload; | |
| if (!dist?.tarball?.startsWith('https://registry.npmjs.org/qca-sdk/-/')) { | |
| throw new Error(`Unexpected registry tarball URL: ${String(dist?.tarball)}`); | |
| } | |
| if (!Array.isArray(dist.signatures) || dist.signatures.length === 0) { | |
| throw new Error('Published package has no registry signature.'); | |
| } | |
| if (dist.attestations?.provenance?.predicateType !== 'https://slsa.dev/provenance/v1') { | |
| throw new Error('Published package has no SLSA provenance attestation.'); | |
| } | |
| process.stdout.write(dist.tarball); | |
| NODE | |
| ) | |
| registry_tarball_file=$(mktemp) | |
| curl --proto '=https' --tlsv1.2 --location --fail --silent --show-error \ | |
| --connect-timeout 10 --max-time 120 --output "$registry_tarball_file" "$registry_tarball" | |
| registry_sha256=$(sha256sum "$registry_tarball_file" | cut -d ' ' -f 1) | |
| if [[ "$registry_sha256" != "$TARBALL_SHA256" ]]; then | |
| echo "Registry tarball does not match the approved artifact." >&2 | |
| exit 1 | |
| fi | |
| if [[ "$REGISTRY_EXISTED" == false ]]; then | |
| selected=$(npm view "$PACKAGE_NAME" "dist-tags.$DIST_TAG" --registry "$NPM_REGISTRY") | |
| if [[ "$selected" != "$RELEASE_VERSION" ]]; then | |
| echo "$DIST_TAG points to $selected instead of $RELEASE_VERSION." >&2 | |
| exit 1 | |
| fi | |
| fi | |
| - name: Verify the installed public package | |
| run: | | |
| set -euo pipefail | |
| project_dir=$(mktemp -d) | |
| cache_dir=$(mktemp -d) | |
| trap 'rm -rf "$project_dir" "$cache_dir"' EXIT | |
| cd "$project_dir" | |
| npm init --yes >/dev/null | |
| npm install --save-exact --ignore-scripts --no-audit --no-fund \ | |
| --registry "$NPM_REGISTRY" --cache "$cache_dir" \ | |
| "$PACKAGE_NAME@$RELEASE_VERSION" | |
| node <<'NODE' | |
| const assert = require('node:assert/strict'); | |
| const expected = process.env.RELEASE_VERSION; | |
| assert.equal(require('qca-sdk/package.json').version, expected); | |
| const root = require('qca-sdk'); | |
| const forward = require('qca-sdk/forward'); | |
| const managed = require('qca-sdk/managed'); | |
| assert.equal(typeof root.ForwardClient, 'function'); | |
| assert.equal(typeof root.ManagedClient, 'function'); | |
| assert.equal(typeof forward.default, 'function'); | |
| assert.equal(typeof managed.default, 'function'); | |
| NODE | |
| node --input-type=module <<'NODE' | |
| import assert from 'node:assert/strict'; | |
| const root = await import('qca-sdk'); | |
| const forward = await import('qca-sdk/forward'); | |
| const managed = await import('qca-sdk/managed'); | |
| assert.equal(typeof root.ForwardClient, 'function'); | |
| assert.equal(typeof root.ManagedClient, 'function'); | |
| assert.equal(typeof forward.default, 'function'); | |
| assert.equal(typeof managed.default, 'function'); | |
| NODE | |
| npm audit signatures --registry "$NPM_REGISTRY" --cache "$cache_dir" | |
| echo "Verified CJS, ESM, subpaths, version, and signatures for $PACKAGE_NAME@$RELEASE_VERSION." >> "$GITHUB_STEP_SUMMARY" | |
| github-release: | |
| name: publish release notes | |
| needs: [preflight, verify] | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| RELEASE_VERSION: ${{ inputs.version }} | |
| RELEASE_COMMIT_SHA: ${{ inputs.commit_sha }} | |
| RELEASE_PRERELEASE: ${{ needs.preflight.outputs.dist_tag == 'next' }} | |
| steps: | |
| - name: Check out the approved commit | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 | |
| with: | |
| ref: ${{ inputs.commit_sha }} | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - name: Create or verify GitHub Release | |
| run: | | |
| python3 .github/scripts/release_notes.py publish \ | |
| --version "$RELEASE_VERSION" \ | |
| --commit-sha "$RELEASE_COMMIT_SHA" \ | |
| --prerelease "$RELEASE_PRERELEASE" |