| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
- name: Release
- # Manually triggered ("Run workflow"). On trigger it:
- # 1. reads the version from package.json,
- # 2. promotes `## [Unreleased]` content into `## [<version>]` in
- # CHANGELOG.md (and commits + pushes that change back to main), so
- # the published release notes are never sparse just because the
- # maintainer didn't pre-stage the [<version>] block by hand,
- # 3. builds a self-contained bundle for every platform (one runner — there's no
- # native compilation, so cross-packaging is fine),
- # 4. creates the GitHub Release (tag v<version>) with all archives, using the
- # release notes from CHANGELOG.md,
- # 5. publishes the npm thin-installer (shim + per-platform packages).
- #
- # Before triggering: bump package.json. CHANGELOG.md entries can live under
- # `## [Unreleased]` — step 2 takes care of moving them. Set the NPM_TOKEN secret.
- on:
- workflow_dispatch: {}
- permissions:
- contents: write # create the GitHub Release + tag, push the CHANGELOG promote
- jobs:
- release:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v6
- with:
- # Default checkout is detached at a SHA; we need an actual branch
- # so the CHANGELOG-promote commit knows where to push.
- ref: ${{ github.ref }}
- - uses: actions/setup-node@v6
- with:
- node-version: 22
- registry-url: https://registry.npmjs.org
- - run: npm ci
- - name: Ensure zip/unzip
- run: sudo apt-get update -qq && sudo apt-get install -y -qq zip unzip
- - name: Resolve version
- id: ver
- run: echo "version=$(node -p "require('./package.json').version")" >> "$GITHUB_OUTPUT"
- - name: Promote [Unreleased] → [<version>] in CHANGELOG.md
- # Idempotent: a no-op if [Unreleased] is empty OR if the previous
- # run already moved everything. Auto-commit + push the change back
- # so the version block on main is the source of truth going
- # forward (and so subsequent extract-release-notes.mjs calls
- # surface the full content even if this run is re-triggered).
- run: |
- set -euo pipefail
- V="${{ steps.ver.outputs.version }}"
- before=$(git rev-parse HEAD)
- node scripts/prepare-release.mjs "$V"
- if git diff --quiet -- CHANGELOG.md; then
- echo "CHANGELOG.md unchanged — nothing to commit."
- else
- git config user.name "github-actions[bot]"
- git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
- git add CHANGELOG.md
- git commit -m "docs(changelog): promote [Unreleased] into [${V}]" -m "[skip ci] Auto-generated by Release workflow."
- # Push to the branch the workflow was triggered on (main).
- git push origin "HEAD:${GITHUB_REF#refs/heads/}"
- fi
- - name: Build all platform bundles
- run: |
- for t in darwin-arm64 darwin-x64 linux-x64 linux-arm64 win32-x64 win32-arm64; do
- bash scripts/build-bundle.sh "$t"
- done
- ls -lh release
- - name: Generate SHA256SUMS
- # Published as a release asset; the npm launcher verifies downloaded
- # bundles against it (basenames only, so its path.basename match works).
- run: |
- ( cd release && sha256sum codegraph-* > SHA256SUMS )
- cat release/SHA256SUMS
- - name: Release notes from CHANGELOG.md
- # The [<version>] block was guaranteed-populated by the
- # "Promote" step above, so the [Unreleased] fallback should
- # never be needed in practice. Kept for defense-in-depth.
- run: |
- V="${{ steps.ver.outputs.version }}"
- node scripts/extract-release-notes.mjs "$V" > notes.md 2>/dev/null \
- || node scripts/extract-release-notes.mjs Unreleased > notes.md 2>/dev/null || true
- if [ ! -s notes.md ]; then
- echo "::error::No release notes in CHANGELOG.md for [$V] or [Unreleased]."
- exit 1
- fi
- echo "----- release notes -----"; cat notes.md
- - name: Create GitHub Release
- env:
- GH_TOKEN: ${{ github.token }}
- run: |
- TAG="v${{ steps.ver.outputs.version }}"
- # Idempotent: create the release once, otherwise (re-run) refresh assets.
- if gh release view "$TAG" >/dev/null 2>&1; then
- gh release upload "$TAG" release/codegraph-* release/SHA256SUMS --clobber
- else
- gh release create "$TAG" release/codegraph-* release/SHA256SUMS --title "$TAG" --notes-file notes.md
- fi
- - name: Publish to npm
- env:
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- run: |
- V="${{ steps.ver.outputs.version }}"
- bash scripts/pack-npm.sh "$V"
- # Platform packages first, then the main shim (which depends on them).
- # Skip any already on the registry so a re-run only fills in gaps.
- for dir in release/npm/codegraph-* release/npm/main; do
- name=$(node -p "require('./$dir/package.json').name")
- if npm view "$name@$V" version >/dev/null 2>&1; then
- echo "skip $name@$V (already published)"
- else
- echo "publishing $name@$V"
- ( cd "$dir" && npm publish --access public )
- fi
- done
- - name: Verify every package is actually on the registry
- run: |
- V="${{ steps.ver.outputs.version }}"
- # npm publish can print success without persisting; confirm against the
- # registry (with retries for propagation) so green means really shipped.
- for dir in release/npm/codegraph-* release/npm/main; do
- name=$(node -p "require('./$dir/package.json').name")
- ok=
- for i in 1 2 3 4 5 6; do
- if npm view "$name@$V" version >/dev/null 2>&1; then ok=1; break; fi
- echo "waiting for $name@$V to appear ($i)…"; sleep 10
- done
- [ -n "$ok" ] || { echo "::error::$name@$V never appeared on the registry"; exit 1; }
- echo "verified $name@$V"
- done
- - name: Sync packages to npmmirror
- # npmmirror/cnpm mirror lazily and frequently never pull the per-platform
- # optionalDependencies on their own, so `npm i` there fails with
- # "no prebuilt bundle" (issue #303). Nudge a sync now so mirror users get
- # the bundle without waiting. Best-effort — the launcher also self-heals
- # from GitHub Releases — so a mirror hiccup never fails the release.
- continue-on-error: true
- run: |
- for dir in release/npm/codegraph-* release/npm/main; do
- name=$(node -p "require('./$dir/package.json').name")
- enc=$(node -p "encodeURIComponent(require('./$dir/package.json').name)")
- echo "sync $name"
- curl -s -X PUT "https://registry.npmmirror.com/-/package/$enc/syncs" || true
- echo
- done
|