0.28.8 #6
Workflow file for this run
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 | |
| # Triggered by tag pushes (preferred) or manual workflow_dispatch (for re-runs). | |
| # | |
| # Authentication: Trusted Publishing via OIDC. No NPM_TOKEN secret needed. | |
| # Configured at: https://www.npmjs.com/package/taskplane/access | |
| # Trusted publisher: HenryLach/taskplane @ release.yml | |
| # | |
| # Flow: | |
| # 1. Checkout the tagged commit | |
| # 2. Validate tag name matches package.json version (no drift allowed) | |
| # 3. Re-run tests (belt-and-suspenders; PR CI already validated main) | |
| # 4. Publish to npm with --provenance attestation | |
| # 5. Create GitHub release with notes extracted from CHANGELOG.md | |
| # | |
| # Manual override: trigger via Actions UI with `tag` input (e.g. `v0.28.5`). | |
| on: | |
| push: | |
| tags: | |
| - "v*" | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: "Existing tag to release (e.g., v0.28.5)" | |
| required: true | |
| type: string | |
| permissions: | |
| contents: write # for creating GitHub release | |
| id-token: write # for npm OIDC trusted publishing | |
| jobs: | |
| release: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| steps: | |
| - name: Determine tag ref | |
| id: ref | |
| run: | | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | |
| echo "ref=${{ github.event.inputs.tag }}" >> "$GITHUB_OUTPUT" | |
| echo "tag=${{ github.event.inputs.tag }}" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "ref=${GITHUB_REF}" >> "$GITHUB_OUTPUT" | |
| echo "tag=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Checkout tagged commit | |
| uses: actions/checkout@v6 | |
| with: | |
| ref: ${{ steps.ref.outputs.ref }} | |
| fetch-depth: 0 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: "24" | |
| registry-url: "https://registry.npmjs.org" | |
| cache: npm | |
| cache-dependency-path: extensions/package-lock.json | |
| - name: Verify npm version supports OIDC Trusted Publishing | |
| # OIDC Trusted Publishing for npm requires npm 11.5.1+. | |
| # Node 24 LTS ships with npm 11.x natively, so this is just a | |
| # belt-and-suspenders check + future-proofing in case a Node 24 | |
| # patch ever ships with an older npm. The `install -g npm@latest` | |
| # is a no-op when the bundled version is already current. | |
| run: | | |
| echo "Node version: $(node --version)" | |
| echo "npm version (pre): $(npm --version)" | |
| npm install -g npm@latest | |
| echo "npm version (post): $(npm --version)" | |
| - name: Validate tag matches package.json version | |
| id: version | |
| run: | | |
| PKG_VERSION=$(node -p "require('./package.json').version") | |
| TAG_NAME="${{ steps.ref.outputs.tag }}" | |
| TAG_VERSION="${TAG_NAME#v}" | |
| echo "package_version=$PKG_VERSION" >> "$GITHUB_OUTPUT" | |
| echo "tag_version=$TAG_VERSION" >> "$GITHUB_OUTPUT" | |
| echo "tag_name=$TAG_NAME" >> "$GITHUB_OUTPUT" | |
| if [ "$PKG_VERSION" != "$TAG_VERSION" ]; then | |
| echo "::error::Tag $TAG_NAME (version $TAG_VERSION) does not match package.json version $PKG_VERSION. Refusing to publish a mismatched release." | |
| exit 1 | |
| fi | |
| echo "✅ Version match: $PKG_VERSION" | |
| - name: Install extension dependencies | |
| run: npm ci --prefix extensions | |
| - name: Run tests (release gate) | |
| run: | | |
| cd extensions | |
| # Same fast-suite invocation CI uses on PR/push to main. | |
| node --experimental-strip-types --experimental-test-module-mocks --no-warnings \ | |
| --import ./tests/loader.mjs \ | |
| --test $(ls tests/*.test.ts | grep -v '\.integration\.test\.ts\|execution-path-resolution\|orch-pure-functions\|project-config-loader' | tr '\n' ' ') | |
| - name: CLI smoke checks | |
| run: | | |
| node bin/taskplane.mjs help | |
| node bin/taskplane.mjs version | |
| - name: Publish to npm with provenance | |
| run: npm publish --provenance --access public | |
| - name: Verify npm publish landed | |
| run: | | |
| # npm registry can lag a few seconds; poll for up to ~30s. | |
| for i in 1 2 3 4 5 6; do | |
| REGISTRY_VERSION=$(npm view taskplane version 2>/dev/null || echo "") | |
| if [ "$REGISTRY_VERSION" = "${{ steps.version.outputs.tag_version }}" ]; then | |
| echo "✅ npm registry shows version $REGISTRY_VERSION" | |
| exit 0 | |
| fi | |
| echo "Registry shows '$REGISTRY_VERSION', expected '${{ steps.version.outputs.tag_version }}'. Retry $i/6 in 5s..." | |
| sleep 5 | |
| done | |
| echo "::error::npm registry did not propagate the new version within 30s. Check https://www.npmjs.com/package/taskplane manually." | |
| exit 1 | |
| - name: Extract changelog section for this version | |
| # Writes the section between `## [VERSION]` and the next `## [` heading | |
| # to a file. Avoids using `${{ }}` interpolation for multi-line content | |
| # in subsequent shell commands — markdown bullets/parens/backticks would | |
| # be mis-parsed as shell syntax (subshells, command substitution, etc). | |
| run: | | |
| VERSION="${{ steps.version.outputs.tag_version }}" | |
| awk -v v="^## \\\\[$VERSION\\\\]" ' | |
| $0 ~ v { found=1; next } | |
| found && /^## \[/ { exit } | |
| found { print } | |
| ' CHANGELOG.md > release-notes.md | |
| if [ ! -s release-notes.md ]; then | |
| echo "::warning::No CHANGELOG section found for version $VERSION; release notes will be sparse." | |
| echo "See [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/main/CHANGELOG.md) for details." > release-notes.md | |
| fi | |
| echo "--- release-notes.md preview ---" | |
| head -20 release-notes.md | |
| echo "..." | |
| echo "(total lines: $(wc -l < release-notes.md))" | |
| - name: Create GitHub release | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| TAG="${{ steps.version.outputs.tag_name }}" | |
| # Idempotent: if the release already exists (e.g. retry after a partial | |
| # failure), skip rather than fail the workflow. | |
| if gh release view "$TAG" >/dev/null 2>&1; then | |
| echo "::notice::GitHub release $TAG already exists; skipping creation." | |
| exit 0 | |
| fi | |
| # Use --notes-file (not --notes "$VAR") so multi-line markdown with | |
| # backticks/parens/asterisks isn't subjected to shell parsing. | |
| gh release create "$TAG" \ | |
| --title "$TAG" \ | |
| --notes-file release-notes.md \ | |
| --verify-tag | |
| - name: Summary | |
| run: | | |
| echo "### 🚀 Released ${{ steps.version.outputs.tag_name }}" >> "$GITHUB_STEP_SUMMARY" | |
| echo "" >> "$GITHUB_STEP_SUMMARY" | |
| echo "- **npm**: https://www.npmjs.com/package/taskplane/v/${{ steps.version.outputs.tag_version }}" >> "$GITHUB_STEP_SUMMARY" | |
| echo "- **GitHub**: https://github.com/${{ github.repository }}/releases/tag/${{ steps.version.outputs.tag_name }}" >> "$GITHUB_STEP_SUMMARY" | |
| echo "- **Provenance**: attached (verifiable via \`npm audit signatures\`)" >> "$GITHUB_STEP_SUMMARY" |