Publish tarball to GitHub Release #5
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: Publish tarball to GitHub Release | |
| # Manual fallback for the tarball distribution channel. Packs | |
| # @anarchitecture/ghost and attaches the .tgz to a GitHub Release, so consumers can: | |
| # | |
| # npm install https://github.com/block/ghost/releases/download/<tag>/<file>.tgz | |
| # | |
| # The normal path is release.yml, which attaches the tarball automatically on | |
| # every Changesets publish. This workflow is dispatch-only so a Changesets- | |
| # created tag does not fire both workflows and race on the same Release. Use it | |
| # to (re)cut a tarball for an existing version without a fresh npm publish. | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: "Version to release (must match packages/ghost/package.json)" | |
| required: true | |
| ref: | |
| description: "Git ref to pack and attach to the release" | |
| required: true | |
| default: "main" | |
| permissions: | |
| contents: write | |
| concurrency: | |
| group: tarball-release-${{ github.ref }} | |
| cancel-in-progress: false | |
| jobs: | |
| tarball: | |
| name: Pack and release | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| ref: ${{ inputs.ref }} | |
| # No setup-node and no pnpm/action-setup — both would trip zizmor's | |
| # cache-poisoning rule because any GitHub-official setup action is | |
| # treated as cache-capable regardless of whether caching is enabled. | |
| # ubuntu-latest ships Node 20 + corepack, which satisfies our | |
| # engines.node (>=18). Corepack reads `packageManager` from root | |
| # package.json to install the exact pinned pnpm version with no | |
| # cross-branch cache store. | |
| - run: node --version && corepack enable | |
| - name: Validate requested version | |
| env: | |
| INPUT_VERSION: ${{ inputs.version }} | |
| run: | | |
| PACKAGE_VERSION="$(node -p "require('./packages/ghost/package.json').version")" | |
| if [ "$PACKAGE_VERSION" != "$INPUT_VERSION" ]; then | |
| echo "Requested version $INPUT_VERSION does not match packages/ghost/package.json version $PACKAGE_VERSION." | |
| exit 1 | |
| fi | |
| - run: pnpm install --frozen-lockfile | |
| - name: Build | |
| run: pnpm --filter @anarchitecture/ghost build | |
| # `pnpm --filter <pkg> pack` writes the tarball to the workspace root, | |
| # not the package dir, in pnpm 10. Force it into a known staging dir so | |
| # the release step can glob a single location deterministically. | |
| - name: Pack | |
| run: | | |
| mkdir -p dist-tarball | |
| pnpm --filter @anarchitecture/ghost pack --pack-destination "$GITHUB_WORKSPACE/dist-tarball" | |
| ls -la dist-tarball | |
| # Resolve the release tag. Inputs from workflow_dispatch are attacker- | |
| # controlled (anyone with Actions write can trigger). Pass them in via | |
| # `env:` and reference as shell variables so they can't be interpolated | |
| # as shell syntax — that's what the semgrep shell-injection rule wants. | |
| - name: Resolve tag | |
| id: tag | |
| env: | |
| INPUT_VERSION: ${{ inputs.version }} | |
| run: | | |
| TAG="anarchitecture-ghost@$INPUT_VERSION" | |
| echo "tag=$TAG" >> "$GITHUB_OUTPUT" | |
| echo "target=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" | |
| - name: Create or update GitHub Release | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| TAG: ${{ steps.tag.outputs.tag }} | |
| TARGET_SHA: ${{ steps.tag.outputs.target }} | |
| INPUT_VERSION: ${{ inputs.version }} | |
| run: | | |
| ASSET="dist-tarball/anarchitecture-ghost-${INPUT_VERSION}.tgz" | |
| if [ ! -f "$ASSET" ]; then | |
| echo "Expected packed asset missing: $ASSET" | |
| exit 1 | |
| fi | |
| if gh release view "$TAG" >/dev/null 2>&1; then | |
| gh release edit "$TAG" --title "$TAG" --target "$TARGET_SHA" | |
| gh release upload "$TAG" "$ASSET" --clobber | |
| else | |
| gh release create "$TAG" \ | |
| --title "$TAG" \ | |
| --target "$TARGET_SHA" \ | |
| --generate-notes \ | |
| "$ASSET" | |
| fi |