chore(deps): update anthropics/claude-code-action action to v1.0.210 #357
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: PR Build Test | |
| on: | |
| issue_comment: | |
| types: [created] | |
| # Cancel any in-progress runs for the same PR when a new /build-test is triggered | |
| concurrency: | |
| group: build-test-pr-${{ github.event.issue.number }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| id-token: write | |
| jobs: | |
| # Gate job to check if we should run the build | |
| check-trigger: | |
| name: Check Trigger | |
| runs-on: ubuntu-latest | |
| if: github.event.issue.pull_request && contains(github.event.comment.body, '/build-test') | |
| outputs: | |
| pr_number: ${{ steps.pr-info.outputs.pr_number }} | |
| pr_sha: ${{ steps.pr-info.outputs.pr_sha }} | |
| sign_windows: ${{ steps.parse-flags.outputs.sign_windows }} | |
| sign_windows_digicert: ${{ steps.parse-flags.outputs.sign_windows_digicert }} | |
| prerelease: ${{ steps.parse-flags.outputs.prerelease }} | |
| comment_id: ${{ steps.react.outputs.comment_id }} | |
| steps: | |
| - name: Parse command flags | |
| id: parse-flags | |
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 | |
| with: | |
| script: | | |
| const comment = context.payload.comment.body; | |
| const flags = comment.split(/\s+/); | |
| const signWindowsDigicert = flags.includes('--sign-windows-digicert'); | |
| const signWindowsAzure = flags.includes('--sign-windows'); | |
| const signWindows = signWindowsAzure && !signWindowsDigicert; | |
| const prerelease = flags.includes('--prerelease'); | |
| core.setOutput('sign_windows', signWindows ? 'true' : 'false'); | |
| core.setOutput('sign_windows_digicert', signWindowsDigicert ? 'true' : 'false'); | |
| core.setOutput('prerelease', prerelease ? 'true' : 'false'); | |
| if (signWindowsDigicert) { | |
| core.info('🔐 Windows signing enabled via --sign-windows-digicert flag (DigiCert KeyLocker)'); | |
| if (signWindowsAzure) { | |
| core.warning('Both --sign-windows and --sign-windows-digicert were specified; using DigiCert and skipping Azure'); | |
| } | |
| } else if (signWindows) { | |
| core.info('🔐 Windows signing enabled via --sign-windows flag (Azure Trusted Signing)'); | |
| } | |
| if (prerelease) { | |
| core.info('🧪 Pre-release build enabled via --prerelease flag'); | |
| } | |
| - name: Check write permission | |
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 | |
| with: | |
| script: | | |
| const commenter = context.payload.comment.user.login; | |
| const { data: permissionLevel } = await github.rest.repos.getCollaboratorPermissionLevel({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| username: commenter | |
| }); | |
| const allowed = ['admin', 'write', 'maintain'].includes(permissionLevel.permission); | |
| if (!allowed) { | |
| core.setFailed(`❌ ${commenter} does not have write access. Only collaborators with write permission can trigger builds.`); | |
| return; | |
| } | |
| core.info(`✅ ${commenter} has ${permissionLevel.permission} permission`); | |
| - name: React to comment | |
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 | |
| id: react | |
| with: | |
| script: | | |
| await github.rest.reactions.createForIssueComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| comment_id: context.payload.comment.id, | |
| content: 'eyes' | |
| }); | |
| core.setOutput('comment_id', context.payload.comment.id); | |
| - name: Get PR info | |
| id: pr-info | |
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 | |
| with: | |
| script: | | |
| const pr = await github.rest.pulls.get({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| pull_number: context.issue.number | |
| }); | |
| const isFork = pr.data.head.repo.full_name !== `${context.repo.owner}/${context.repo.repo}`; | |
| if (isFork) { | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: pr.data.number, | |
| body: '❌ `/build-test` is disabled for forked PRs to protect signing secrets. Please open a PR from a branch in this repository if you need a build.' | |
| }); | |
| core.setFailed('❌ /build-test is disabled for forked PRs to protect signing secrets.'); | |
| return; | |
| } | |
| core.setOutput('pr_number', pr.data.number); | |
| core.setOutput('pr_sha', pr.data.head.sha); | |
| core.setOutput('base_ref', pr.data.base.ref); | |
| - name: Check if branch is up-to-date with base | |
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 | |
| with: | |
| script: | | |
| const baseBranch = '${{ steps.pr-info.outputs.base_ref }}'; | |
| const headSha = '${{ steps.pr-info.outputs.pr_sha }}'; | |
| const prNumber = ${{ steps.pr-info.outputs.pr_number }}; | |
| // Compare base branch with PR head | |
| const comparison = await github.rest.repos.compareCommits({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| base: headSha, | |
| head: baseBranch | |
| }); | |
| // If base is ahead of the PR branch, it needs a rebase | |
| if (comparison.data.ahead_by > 0) { | |
| const behindCount = comparison.data.ahead_by; | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: prNumber, | |
| body: `⚠️ This branch is **${behindCount} commit${behindCount > 1 ? 's' : ''} behind \`${baseBranch}\`**. Please rebase before running \`/build-test\` to ensure artifacts are built on the latest code.\n\n\`\`\`bash\ngit fetch origin ${baseBranch}\ngit rebase origin/${baseBranch}\ngit push --force-with-lease\n\`\`\`` | |
| }); | |
| core.setFailed(`Branch is ${behindCount} commits behind ${baseBranch}. Rebase required.`); | |
| } else { | |
| core.info(`✅ Branch is up-to-date with ${baseBranch}`); | |
| } | |
| build: | |
| name: Build on ${{ matrix.os }}${{ matrix.arch && format(' ({0})', matrix.arch) || '' }} | |
| needs: check-trigger | |
| runs-on: ${{ matrix.os }} | |
| # Activate the `artifact-signing` environment only for the Windows matrix | |
| # row when Azure Trusted Signing is requested (`--sign-windows`). The Azure | |
| # OIDC federated credential is scoped to | |
| # `repo:stacklok/toolhive-studio:environment:artifact-signing`, so only | |
| # the Windows signing job should run in that environment for the token | |
| # exchange to succeed. DigiCert signing (`--sign-windows-digicert`) uses | |
| # repo-level SM_* secrets and does not need this environment. Scoping to | |
| # `matrix.platform == 'win32'` keeps the Linux/macOS matrix rows out of | |
| # the environment so they don't receive environment-scoped signing secrets | |
| # or trigger environment approvals. Leaving it empty for non-signing builds | |
| # keeps them free of approvals. | |
| environment: ${{ needs.check-trigger.outputs.sign_windows == 'true' && matrix.platform == 'win32' && 'artifact-signing' || '' }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - os: ubuntu-24.04-arm | |
| arch: arm64 | |
| platform: linux | |
| - os: ubuntu-latest | |
| arch: x64 | |
| platform: linux | |
| - os: windows-latest | |
| arch: x64 | |
| platform: win32 | |
| - os: macos-15-intel | |
| arch: x64 | |
| platform: darwin | |
| - os: macos-latest | |
| arch: arm64 | |
| platform: darwin | |
| env: | |
| NODE_OPTIONS: '--max_old_space_size=4096' | |
| PR_NUMBER: ${{ needs.check-trigger.outputs.pr_number }} | |
| steps: | |
| - name: Checkout PR branch | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 | |
| with: | |
| ref: ${{ needs.check-trigger.outputs.pr_sha }} | |
| - name: Setup | |
| uses: ./.github/actions/setup | |
| - name: Set version | |
| id: version | |
| shell: bash | |
| run: | | |
| if [ "${{ needs.check-trigger.outputs.prerelease }}" = "true" ]; then | |
| VERSION="0.0.0-beta.${{ env.PR_NUMBER }}" | |
| else | |
| VERSION="0.0.0-pr.${{ env.PR_NUMBER }}" | |
| fi | |
| echo "Setting version to: $VERSION" | |
| npm version $VERSION --no-git-tag-version --allow-same-version | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| echo "artifact_prefix=ToolHive-$VERSION" >> $GITHUB_OUTPUT | |
| - name: Setup macOS code signing | |
| uses: ./.github/actions/setup-macos-codesign | |
| if: runner.os == 'macOS' | |
| with: | |
| apple-certificate: ${{ secrets.APPLE_CERTIFICATE }} | |
| apple-certificate-password: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} | |
| keychain-password: ${{ secrets.KEYCHAIN_PASSWORD }} | |
| apple-api-key: ${{ secrets.APPLE_API_KEY }} | |
| apple-issuer-id: ${{ secrets.APPLE_ISSUER_ID }} | |
| apple-key-id: ${{ secrets.APPLE_KEY_ID }} | |
| - name: Setup Windows code signing (Azure Trusted Signing) | |
| uses: ./.github/actions/setup-azure-trusted-signing | |
| if: runner.os == 'Windows' && needs.check-trigger.outputs.sign_windows == 'true' | |
| with: | |
| azure-client-id: ${{ secrets.AZURE_ARTIFACT_SIGNING_CLIENT_ID }} | |
| azure-tenant-id: ${{ secrets.AZURE_ARTIFACT_SIGNING_TENANT_ID }} | |
| azure-subscription-id: ${{ secrets.AZURE_ARTIFACT_SIGNING_SUBSCRIPTION_ID }} | |
| azure-endpoint: ${{ secrets.AZURE_ARTIFACT_SIGNING_ENDPOINT }} | |
| azure-account-name: ${{ secrets.AZURE_ARTIFACT_SIGNING_ACCOUNT_NAME }} | |
| azure-certificate-profile-name: ${{ secrets.AZURE_ARTIFACT_SIGNING_CERTIFICATE_PROFILE_NAME }} | |
| - name: Setup Windows code signing (DigiCert KeyLocker) | |
| uses: ./.github/actions/setup-windows-codesign | |
| if: runner.os == 'Windows' && needs.check-trigger.outputs.sign_windows_digicert == 'true' | |
| with: | |
| sm-host: ${{ secrets.SM_HOST }} | |
| sm-api-key: ${{ secrets.SM_API_KEY }} | |
| sm-client-cert-file-b64: ${{ secrets.SM_CLIENT_CERT_FILE_B64 }} | |
| sm-client-cert-password: ${{ secrets.SM_CLIENT_CERT_PASSWORD }} | |
| sm-code-signing-cert-sha1-hash: ${{ secrets.SM_CODE_SIGNING_CERT_SHA1_HASH }} | |
| - name: Setup Flatpak (Linux only) | |
| uses: ./.github/actions/setup-flatpak | |
| if: runner.os == 'Linux' | |
| - name: Build App | |
| run: pnpm run make | |
| env: | |
| npm_config_target_platform: ${{ matrix.platform }} | |
| # macOS signing (set by composite action) | |
| APPLE_API_KEY: ${{ env.APPLE_API_KEY_PATH }} | |
| APPLE_ISSUER_ID: ${{ env.APPLE_ISSUER_ID }} | |
| APPLE_KEY_ID: ${{ env.APPLE_KEY_ID }} | |
| - name: Upload flatpak bundle as artifact (Linux only) | |
| if: runner.os == 'Linux' | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 | |
| with: | |
| name: flatpak-bundle-${{ matrix.arch == 'arm64' && 'aarch64' || 'x86_64' }} | |
| path: out/make/**/*.flatpak | |
| retention-days: 1 | |
| - name: Upload artifacts | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 | |
| with: | |
| name: ${{ steps.version.outputs.artifact_prefix }}-${{ matrix.platform }}-${{ matrix.arch }} | |
| path: | | |
| out/make/**/*.dmg | |
| out/make/**/*.zip | |
| out/make/**/*.exe | |
| out/make/**/*.deb | |
| out/make/**/*.rpm | |
| out/make/**/*.tar.gz | |
| out/make/**/*.flatpak | |
| retention-days: 7 | |
| if-no-files-found: error | |
| post-comment: | |
| name: Post Download Links | |
| needs: [check-trigger, build] | |
| runs-on: ubuntu-latest | |
| if: always() && needs.check-trigger.result == 'success' | |
| steps: | |
| - name: Get workflow run URL | |
| id: run-url | |
| run: | | |
| echo "url=${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" >> $GITHUB_OUTPUT | |
| - name: Post comment with results | |
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 | |
| with: | |
| script: | | |
| const prNumber = ${{ needs.check-trigger.outputs.pr_number }}; | |
| const version = `pr-${prNumber}`; | |
| const runUrl = `${{ steps.run-url.outputs.url }}`; | |
| const buildResult = '${{ needs.build.result }}'; | |
| const triggeredBy = '${{ github.event.comment.user.login }}'; | |
| const signWindowsAzure = '${{ needs.check-trigger.outputs.sign_windows }}' === 'true'; | |
| const signWindowsDigicert = '${{ needs.check-trigger.outputs.sign_windows_digicert }}' === 'true'; | |
| const windowsSigningProvider = signWindowsDigicert | |
| ? 'DigiCert KeyLocker' | |
| : signWindowsAzure | |
| ? 'Azure Trusted Signing' | |
| : null; | |
| // Marker to identify bot comments for this workflow | |
| const marker = '<!-- build-test-bot -->'; | |
| const windowsSignedNote = windowsSigningProvider | |
| ? `macOS builds are signed (not notarized). Windows builds are signed and timestamped via ${windowsSigningProvider}. Linux builds are unsigned.` | |
| : 'macOS builds are signed (not notarized). Windows and Linux builds are unsigned.'; | |
| let body; | |
| if (buildResult === 'success') { | |
| body = [ | |
| marker, | |
| '## Build Artifacts for PR #' + prNumber, | |
| '', | |
| '| Platform | Architecture | Status |', | |
| '|----------|--------------|--------|', | |
| '| macOS | arm64 | :white_check_mark: Ready |', | |
| '| macOS | x64 | :white_check_mark: Ready |', | |
| '| Windows | arm64 | :white_check_mark: Ready' + (windowsSigningProvider ? ` (signed via ${windowsSigningProvider})` : '') + ' |', | |
| '| Windows | x64 | :white_check_mark: Ready' + (windowsSigningProvider ? ` (signed via ${windowsSigningProvider})` : '') + ' |', | |
| '| Linux | arm64 | :white_check_mark: Ready |', | |
| '| Linux | x64 | :white_check_mark: Ready |', | |
| '', | |
| '**[Download artifacts from workflow run](' + runUrl + ')**', | |
| '', | |
| '*Version: `' + version + '` | Artifacts expire in 7 days | Triggered by @' + triggeredBy + '*', | |
| '', | |
| '> **Note:** ' + windowsSignedNote | |
| ].join('\n'); | |
| } else { | |
| body = [ | |
| marker, | |
| '## Build Failed for PR #' + prNumber, | |
| '', | |
| 'The build encountered errors. Please check the [workflow run](' + runUrl + ') for details.', | |
| '', | |
| '*Triggered by @' + triggeredBy + '*' | |
| ].join('\n'); | |
| } | |
| // Find existing bot comment | |
| const { data: comments } = await github.rest.issues.listComments({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: prNumber | |
| }); | |
| const botComment = comments.find(comment => comment.body.includes(marker)); | |
| if (botComment) { | |
| // Update existing comment | |
| await github.rest.issues.updateComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| comment_id: botComment.id, | |
| body: body | |
| }); | |
| core.info(`Updated existing comment ${botComment.id}`); | |
| } else { | |
| // Create new comment | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: prNumber, | |
| body: body | |
| }); | |
| core.info('Created new comment'); | |
| } | |
| // Add rocket reaction to original comment on success | |
| const commentId = '${{ needs.check-trigger.outputs.comment_id }}'; | |
| if (buildResult === 'success' && commentId) { | |
| await github.rest.reactions.createForIssueComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| comment_id: commentId, | |
| content: 'rocket' | |
| }); | |
| } |