diff --git a/.github/workflows/collect-prs.yml b/.github/workflows/collect-prs.yml index b420cea..18842f9 100644 --- a/.github/workflows/collect-prs.yml +++ b/.github/workflows/collect-prs.yml @@ -1,75 +1,102 @@ -# This workflow will build a .NET project - -name: collect dotnet-runtime PRs - -on: - schedule: - - cron: '0 0 * * *' - workflow_dispatch: # Allow manual trigger - -concurrency: - group: "pages" - cancel-in-progress: true - -jobs: - summarize: - runs-on: ubuntu-latest - permissions: - contents: write - timeout-minutes: 70 # Message Batches: up to 40 min wait (Program.cs) + one-by-one fallback - outputs: - has_changes: ${{ steps.commit.outputs.has_changes }} - steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - name: Setup .NET - uses: prozolic/Actions/.github/actions/setup-dotnet@main - with: - dotnet-version: 10.0.x - - name: Restore dependencies - run: dotnet restore - - name: Build - run: dotnet build -c Release - - name: configure-pages@v4 latest PRs and create PRs. - run: dotnet run --project ./src/PRDigest.NET/PRDigest.NET.csproj --no-launch-profile -c Release ./archives ./outputs -g - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} - - name: Commit and push changes - id: commit - run: | - git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" - git config --local user.name "github-actions[bot]" - git add ./archives - - if git diff --quiet && git diff --staged --quiet; then - echo "has_changes=false" >> "$GITHUB_OUTPUT" - else - git commit -m "Summarize latest PRs by github-actions[bot]" && git push origin main - echo "has_changes=true" >> "$GITHUB_OUTPUT" - fi - - name: Upload artifact - uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0 - with: - path: ./outputs/ - - deploy: - needs: summarize - permissions: - contents: read - pages: write - id-token: write - environment: - name: github-pages - url: ${{steps.deployment.outputs.page_url}} - runs-on: ubuntu-latest - steps: - - name: Deploy - id: deployment - uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0 - - # NOTE: push with GITHUB_TOKEN won't invoke the event, - # as a workaround, directly call the action. - release: - needs: [summarize, deploy] - if: needs.summarize.outputs.has_changes == 'true' - uses: ./.github/workflows/create-release.yml +# This workflow will build a .NET project + +name: collect dotnet-runtime PRs + +on: + schedule: + - cron: '0 0 * * *' + workflow_dispatch: # Allow manual trigger + +concurrency: + group: "pages" + cancel-in-progress: true + +jobs: + summarize: + runs-on: ubuntu-latest + permissions: + contents: write + id-token: write # GitHub OIDC token for Workload Identity Federation with the Claude API + timeout-minutes: 70 # Message Batches: up to 40 min wait (Program.cs) + one-by-one fallback + outputs: + has_changes: ${{ steps.commit.outputs.has_changes }} + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - name: Setup .NET + uses: prozolic/Actions/.github/actions/setup-dotnet@main + with: + dotnet-version: 10.0.x + - name: Restore dependencies + run: dotnet restore + - name: Build + run: dotnet build -c Release + - name: configure-pages@v4 latest PRs and create PRs. + run: | + fetch_identity_token() { + local token + token=$(curl -fsS -H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \ + "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=https://api.anthropic.com" | jq -er .value) && + printf '%s' "$token" > "$ANTHROPIC_IDENTITY_TOKEN_FILE.tmp" && + mv "$ANTHROPIC_IDENTITY_TOKEN_FILE.tmp" "$ANTHROPIC_IDENTITY_TOKEN_FILE" + } + fetch_identity_token + + # A GitHub ID token expires about 5 minutes after it is issued, while this step can run + # for over 40 minutes (Message Batches). The SDK re-reads the file whenever it refreshes + # its Anthropic access token, so keep the file fresh in the background. + # Every 60 s: an Anthropic token lives at most twice the JWT's remaining lifetime and is + # refreshed 120 s before expiry, and a JWT (jti) can be exchanged only once, so a staler + # file could be read again by the next refresh (jti_reused). + while sleep 60; do + fetch_identity_token || echo "::warning::Failed to refresh the GitHub OIDC token" + done & + refresher=$! + trap 'kill "$refresher"' EXIT + + dotnet run --project ./src/PRDigest.NET/PRDigest.NET.csproj --no-launch-profile -c Release ./archives ./outputs -g + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ANTHROPIC_FEDERATION_RULE_ID: ${{ secrets.ANTHROPIC_FEDERATION_RULE_ID }} + ANTHROPIC_ORGANIZATION_ID: ${{ secrets.ANTHROPIC_ORGANIZATION_ID }} + ANTHROPIC_SERVICE_ACCOUNT_ID: ${{ secrets.ANTHROPIC_SERVICE_ACCOUNT_ID }} + ANTHROPIC_WORKSPACE_ID: ${{ secrets.ANTHROPIC_WORKSPACE_ID }} + ANTHROPIC_IDENTITY_TOKEN_FILE: ${{ runner.temp }}/gha-jwt + - name: Commit and push changes + id: commit + run: | + git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" + git config --local user.name "github-actions[bot]" + git add ./archives + + if git diff --quiet && git diff --staged --quiet; then + echo "has_changes=false" >> "$GITHUB_OUTPUT" + else + git commit -m "Summarize latest PRs by github-actions[bot]" && git push origin main + echo "has_changes=true" >> "$GITHUB_OUTPUT" + fi + - name: Upload artifact + uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0 + with: + path: ./outputs/ + + deploy: + needs: summarize + permissions: + contents: read + pages: write + id-token: write + environment: + name: github-pages + url: ${{steps.deployment.outputs.page_url}} + runs-on: ubuntu-latest + steps: + - name: Deploy + id: deployment + uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0 + + # NOTE: push with GITHUB_TOKEN won't invoke the event, + # as a workaround, directly call the action. + release: + needs: [summarize, deploy] + if: needs.summarize.outputs.has_changes == 'true' + uses: ./.github/workflows/create-release.yml diff --git a/src/PRDigest.NET/Program.cs b/src/PRDigest.NET/Program.cs index f38a1e2..440ed70 100644 --- a/src/PRDigest.NET/Program.cs +++ b/src/PRDigest.NET/Program.cs @@ -341,7 +341,7 @@ async ValueTask SummarizeSequentiallyAsync(IAnthropicClient client, PullRequestI IAnthropicClient CreateAnthropicClient() { - // Configures ANTHROPIC_API_KEY. + // Configures ANTHROPIC_API_KEY (local) or Workload Identity Federation (ANTHROPIC_IDENTITY_TOKEN_FILE etc., GitHub Actions). AnthropicClient anthropicClient = new(); return anthropicClient.WithOptions(options => options with {