Release #32
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: | |
| tag: | |
| description: 'Tag to release (must exist, created by bump-version.sh)' | |
| required: true | |
| type: string | |
| permissions: | |
| contents: write | |
| id-token: write | |
| attestations: write | |
| actions: read | |
| jobs: | |
| # Job 1: Validate tag and resolve commit | |
| prepare: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| tag: ${{ steps.version.outputs.tag }} | |
| version: ${{ steps.version.outputs.version }} | |
| commit: ${{ steps.version.outputs.commit }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Validate tag and version | |
| id: version | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| TAG="${{ inputs.tag }}" | |
| # Validate tag format | |
| if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then | |
| echo "::error::Invalid tag format: $TAG. Expected: v1.2.3" | |
| exit 1 | |
| fi | |
| VERSION="${TAG#v}" | |
| # Verify tag exists locally (should be created by bump-version.sh) | |
| if ! git rev-parse "$TAG" >/dev/null 2>&1; then | |
| echo "::error::Tag $TAG not found. Run bump-version.sh first and push the tag." | |
| exit 1 | |
| fi | |
| COMMIT=$(git rev-list -n 1 "$TAG") | |
| # Verify package.json version matches tag | |
| PKG_VERSION=$(node -p "require('./npm/webcodecs-ffmpeg/package.json').version") | |
| if [[ "$PKG_VERSION" != "$VERSION" ]]; then | |
| echo "::error::package.json version ($PKG_VERSION) doesn't match tag ($VERSION)" | |
| exit 1 | |
| fi | |
| echo "tag=$TAG" >> "$GITHUB_OUTPUT" | |
| echo "version=$VERSION" >> "$GITHUB_OUTPUT" | |
| echo "commit=$COMMIT" >> "$GITHUB_OUTPUT" | |
| echo "Releasing $TAG (version $VERSION) at commit $COMMIT" | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| registry-url: 'https://registry.npmjs.org' | |
| - name: Verify version not published | |
| run: | | |
| VERSION="${{ steps.version.outputs.version }}" | |
| PKG="@pproenca/webcodecs-ffmpeg" | |
| # Check if version already exists on npm | |
| if npm view "${PKG}@${VERSION}" version 2>/dev/null; then | |
| echo "::error::Version $VERSION already published to npm" | |
| exit 1 | |
| fi | |
| echo "Version $VERSION not yet published - OK" | |
| # Job 2: Find CI artifacts | |
| check-artifacts: | |
| needs: prepare | |
| runs-on: ubuntu-latest | |
| outputs: | |
| run_id: ${{ steps.search.outputs.run_id }} | |
| steps: | |
| - name: Search for CI artifacts | |
| id: search | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| COMMIT: ${{ needs.prepare.outputs.commit }} | |
| run: | | |
| echo "Searching for CI artifacts..." | |
| RUN_ID=$(gh api "repos/${{ github.repository }}/actions/workflows/ci.yml/runs" \ | |
| --jq ".workflow_runs[] | select(.head_sha == \"$COMMIT\" and .conclusion == \"success\") | .id" \ | |
| 2>/dev/null | head -1 || echo "") | |
| if [[ -n "$RUN_ID" ]]; then | |
| echo "Found CI run for commit $COMMIT: $RUN_ID" | |
| else | |
| echo "No CI run for commit $COMMIT, searching for most recent..." | |
| RUN_ID=$(gh api "repos/${{ github.repository }}/actions/workflows/ci.yml/runs?branch=master&status=success&per_page=1" \ | |
| --jq ".workflow_runs[0].id" 2>/dev/null || echo "") | |
| if [[ -z "$RUN_ID" ]]; then | |
| echo "::error::No successful CI run found. Run CI workflow first." | |
| exit 1 | |
| fi | |
| RUN_COMMIT=$(gh api "repos/${{ github.repository }}/actions/runs/$RUN_ID" --jq ".head_sha") | |
| echo "Using CI run $RUN_ID from commit $RUN_COMMIT" | |
| fi | |
| # Verify artifacts exist | |
| ARTIFACT_COUNT=$(gh api "repos/${{ github.repository }}/actions/runs/$RUN_ID/artifacts" \ | |
| --jq '[.artifacts[] | select(.name | startswith("ffmpeg-"))] | length') | |
| if [[ "$ARTIFACT_COUNT" -lt 8 ]]; then | |
| echo "::error::Expected 8 artifacts, found $ARTIFACT_COUNT. CI artifacts may have expired." | |
| exit 1 | |
| fi | |
| echo "Found $ARTIFACT_COUNT artifacts in CI run $RUN_ID" | |
| echo "run_id=$RUN_ID" >> "$GITHUB_OUTPUT" | |
| # Job 3: Create release and publish to npm | |
| release-and-publish: | |
| needs: [prepare, check-artifacts] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ needs.prepare.outputs.tag }} | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| registry-url: 'https://registry.npmjs.org' | |
| - uses: pnpm/action-setup@v4 | |
| with: | |
| version: 9 | |
| - name: Download CI artifacts | |
| uses: dawidd6/action-download-artifact@v6 | |
| with: | |
| workflow: ci.yml | |
| run_id: ${{ needs.check-artifacts.outputs.run_id }} | |
| path: artifacts | |
| name: ffmpeg-* | |
| name_is_regexp: true | |
| - name: Flatten and verify artifacts | |
| run: | | |
| cd artifacts | |
| # Flatten subdirectories | |
| for dir in */; do | |
| [[ -d "$dir" ]] && mv "$dir"* . 2>/dev/null && rmdir "$dir" 2>/dev/null || true | |
| done | |
| # Verify count | |
| shopt -s nullglob | |
| tarballs=(*.tar.gz) | |
| if [[ ${#tarballs[@]} -ne 8 ]]; then | |
| echo "::error::Expected 8 tarballs, found ${#tarballs[@]}" | |
| ls -la | |
| exit 1 | |
| fi | |
| # Verify checksums | |
| for f in *.sha256; do | |
| sha256sum --check "$f" | |
| done | |
| echo "All 8 artifacts verified" | |
| - name: Generate attestations | |
| uses: actions/attest-build-provenance@v2 | |
| with: | |
| subject-path: 'artifacts/*.tar.gz' | |
| - name: Create GitHub release | |
| uses: ncipollo/release-action@v1 | |
| with: | |
| tag: ${{ needs.prepare.outputs.tag }} | |
| commit: ${{ needs.prepare.outputs.commit }} | |
| artifacts: "artifacts/*.tar.gz,artifacts/*.sha256" | |
| generateReleaseNotes: true | |
| allowUpdates: true | |
| - name: Extract and populate npm packages | |
| run: | | |
| # Extract tarballs - each creates <platform>-<tier>/ directory | |
| mkdir -p extracted | |
| for tarball in artifacts/*.tar.gz; do | |
| tar -xzf "$tarball" -C extracted | |
| done | |
| # Move to artifacts directory for populate-artifacts.sh | |
| mv extracted artifacts-extracted | |
| rm -rf artifacts | |
| mv artifacts-extracted artifacts | |
| # populate-artifacts.sh copies lib/include only, doesn't touch package.json | |
| ./scripts/populate-artifacts.sh | |
| - run: cd npm && pnpm publish -r --provenance --access public --no-git-checks | |
| env: | |
| NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} |