|
6 | 6 | pull_request_review_comment: |
7 | 7 | types: [created] |
8 | 8 | pull_request: |
9 | | - types: [opened, synchronize, ready_for_review] |
| 9 | + types: [opened, synchronize, ready_for_review, labeled] |
10 | 10 |
|
11 | 11 | jobs: |
12 | | - auto-review: |
| 12 | + check-author: |
13 | 13 | if: | |
14 | 14 | github.event_name == 'pull_request' && |
15 | 15 | github.event.pull_request.draft == false && |
| 16 | + github.event.pull_request.user.login != 'github-actions[bot]' && |
| 17 | + !startsWith(github.head_ref, 'release/') && |
16 | 18 | !contains(github.event.pull_request.labels.*.name, 'no review') && |
17 | | - !contains(github.event.pull_request.labels.*.name, 'auto-pr') |
| 19 | + !contains(github.event.pull_request.labels.*.name, 'auto-pr') && |
| 20 | + (github.event.action != 'labeled' || github.event.label.name == 'ext-contribution') |
| 21 | + runs-on: ubuntu-latest |
| 22 | + permissions: |
| 23 | + contents: read |
| 24 | + pull-requests: write |
| 25 | + outputs: |
| 26 | + is-team-dev: ${{ steps.check.outputs.is-team-dev }} |
| 27 | + steps: |
| 28 | + - name: Check for ext-contribution label |
| 29 | + id: label-check |
| 30 | + run: | |
| 31 | + if [[ "${{ contains(github.event.pull_request.labels.*.name, 'ext-contribution') }}" == "true" ]]; then |
| 32 | + echo "has-label=true" >> "$GITHUB_OUTPUT" |
| 33 | + else |
| 34 | + echo "has-label=false" >> "$GITHUB_OUTPUT" |
| 35 | + fi |
| 36 | +
|
| 37 | + - name: Checkout config file |
| 38 | + if: steps.label-check.outputs.has-label != 'true' |
| 39 | + uses: actions/checkout@v6 |
| 40 | + with: |
| 41 | + ref: ${{ github.event.pull_request.base.sha }} |
| 42 | + sparse-checkout: .github/auto_assign_config_dev.yml |
| 43 | + fetch-depth: 1 |
| 44 | + |
| 45 | + - name: Check if PR author is a team dev |
| 46 | + id: check |
| 47 | + env: |
| 48 | + PR_AUTHOR: ${{ github.event.pull_request.user.login }} |
| 49 | + run: | |
| 50 | + if [[ "${{ steps.label-check.outputs.has-label }}" == "true" ]]; then |
| 51 | + echo "Author $PR_AUTHOR has ext-contribution label — treating as external" |
| 52 | + echo "is-team-dev=false" >> "$GITHUB_OUTPUT" |
| 53 | + exit 0 |
| 54 | + fi |
| 55 | + TEAM_DEVS=$(yq eval '.reviewGroups | .[] | .[]' .github/auto_assign_config_dev.yml) |
| 56 | + echo "Team devs:" |
| 57 | + echo "$TEAM_DEVS" |
| 58 | + if echo "$TEAM_DEVS" | grep -qxF "$PR_AUTHOR"; then |
| 59 | + echo "Author $PR_AUTHOR is a team dev" |
| 60 | + echo "is-team-dev=true" >> "$GITHUB_OUTPUT" |
| 61 | + else |
| 62 | + echo "Author $PR_AUTHOR is NOT a team dev" |
| 63 | + echo "is-team-dev=false" >> "$GITHUB_OUTPUT" |
| 64 | + fi |
| 65 | +
|
| 66 | + - name: Add ext-contribution label for non-team PRs |
| 67 | + if: | |
| 68 | + steps.check.outputs.is-team-dev == 'false' && |
| 69 | + steps.label-check.outputs.has-label != 'true' && |
| 70 | + (github.event.action == 'opened' || github.event.action == 'ready_for_review') |
| 71 | + env: |
| 72 | + GH_TOKEN: ${{ secrets.ORG_ACCESS_TOKEN }} |
| 73 | + run: | |
| 74 | + gh pr edit ${{ github.event.pull_request.number }} --add-label ext-contribution --repo ${{ github.repository }} || echo "::warning::Could not add label (expected for fork PRs)" |
| 75 | + echo "Added ext-contribution label to PR #${{ github.event.pull_request.number }}" |
| 76 | +
|
| 77 | + auto-review: |
| 78 | + needs: check-author |
| 79 | + if: | |
| 80 | + needs.check-author.result == 'success' && |
| 81 | + needs.check-author.outputs.is-team-dev == 'true' |
18 | 82 | runs-on: ubuntu-latest |
19 | 83 | concurrency: |
20 | 84 | group: claude-auto-review-${{ github.event.pull_request.number }} |
@@ -296,6 +360,90 @@ jobs: |
296 | 360 | gh run rerun "$WORKFLOW_RUN_ID" --repo "${{ github.repository }}" |
297 | 361 | echo "Re-run triggered successfully." |
298 | 362 |
|
| 363 | + notify-ext-contribution: |
| 364 | + needs: check-author |
| 365 | + if: | |
| 366 | + needs.check-author.result == 'success' && |
| 367 | + needs.check-author.outputs.is-team-dev == 'false' && |
| 368 | + github.event.action == 'labeled' && |
| 369 | + github.event.label.name == 'ext-contribution' |
| 370 | + runs-on: ubuntu-latest |
| 371 | + permissions: |
| 372 | + pull-requests: write |
| 373 | + issues: write |
| 374 | + steps: |
| 375 | + - name: Check for existing Slack notification marker |
| 376 | + id: dedup |
| 377 | + env: |
| 378 | + GH_TOKEN: ${{ github.token }} |
| 379 | + run: | |
| 380 | + MARKER="<!-- ext-contribution-slack-sent -->" |
| 381 | + COMMENTS=$(gh api "repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments?per_page=100" --jq '.[].body') |
| 382 | + if echo "$COMMENTS" | grep -qF "$MARKER"; then |
| 383 | + echo "Slack notification already sent for this PR — skipping" |
| 384 | + echo "already-sent=true" >> "$GITHUB_OUTPUT" |
| 385 | + else |
| 386 | + echo "already-sent=false" >> "$GITHUB_OUTPUT" |
| 387 | + fi |
| 388 | +
|
| 389 | + - name: Verify PR author is a decentraland org member |
| 390 | + if: steps.dedup.outputs.already-sent != 'true' |
| 391 | + id: check-org |
| 392 | + env: |
| 393 | + GH_TOKEN: ${{ secrets.ORG_ACCESS_TOKEN }} |
| 394 | + PR_AUTHOR: ${{ github.event.pull_request.user.login }} |
| 395 | + run: | |
| 396 | + if gh api "/orgs/decentraland/members/$PR_AUTHOR" --silent 2>/dev/null; then |
| 397 | + echo "is-member=true" >> "$GITHUB_OUTPUT" |
| 398 | + else |
| 399 | + echo "::notice::PR author $PR_AUTHOR is not a member of decentraland org; Slack notification skipped" |
| 400 | + echo "is-member=false" >> "$GITHUB_OUTPUT" |
| 401 | + fi |
| 402 | +
|
| 403 | + - name: Extract Slack requester tag from PR description |
| 404 | + if: steps.dedup.outputs.already-sent != 'true' && steps.check-org.outputs.is-member == 'true' |
| 405 | + id: extract-slack-tag |
| 406 | + env: |
| 407 | + PR_BODY: ${{ github.event.pull_request.body }} |
| 408 | + run: | |
| 409 | + SLACK_TAG=$(echo "$PR_BODY" | grep -oP '(?<=Requested by ).*?(\(<@U[A-Z0-9]+>\))' | grep -oP '<@U[A-Z0-9]+>' | head -1) |
| 410 | + if [ -n "$SLACK_TAG" ]; then |
| 411 | + echo "Found Slack tag: $SLACK_TAG" |
| 412 | + echo "slack-tag=$SLACK_TAG" >> "$GITHUB_OUTPUT" |
| 413 | + else |
| 414 | + echo "No Slack tag found in PR description, will use GitHub username" |
| 415 | + echo "slack-tag=" >> "$GITHUB_OUTPUT" |
| 416 | + fi |
| 417 | +
|
| 418 | + - name: Post to Slack #explorer-ext-contributions |
| 419 | + if: steps.dedup.outputs.already-sent != 'true' && steps.check-org.outputs.is-member == 'true' |
| 420 | + env: |
| 421 | + SLACK_WEBHOOK_URL: ${{ secrets.EXPLORER_EXT_CONTRIBUTIONS_WEBHOOK }} |
| 422 | + PR_URL: ${{ github.event.pull_request.html_url }} |
| 423 | + PR_AUTHOR_LOGIN: ${{ github.event.pull_request.user.login }} |
| 424 | + SLACK_TAG: ${{ steps.extract-slack-tag.outputs.slack-tag }} |
| 425 | + run: | |
| 426 | + if [ -n "$SLACK_TAG" ]; then |
| 427 | + AUTHOR_REF="$SLACK_TAG" |
| 428 | + else |
| 429 | + AUTHOR_REF="$PR_AUTHOR_LOGIN" |
| 430 | + fi |
| 431 | + PAYLOAD=$(jq -n --arg url "$PR_URL" --arg author "$AUTHOR_REF" \ |
| 432 | + '{"text": "<@U0AJ91P1KBP> review \($url) (initiated by \($author))"}') |
| 433 | + curl -fsS -X POST "$SLACK_WEBHOOK_URL" \ |
| 434 | + -H 'Content-Type: application/json' \ |
| 435 | + -d "$PAYLOAD" |
| 436 | +
|
| 437 | + - name: Post dedup marker comment |
| 438 | + if: steps.dedup.outputs.already-sent != 'true' && steps.check-org.outputs.is-member == 'true' |
| 439 | + env: |
| 440 | + GH_TOKEN: ${{ github.token }} |
| 441 | + run: | |
| 442 | + gh api "repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments" \ |
| 443 | + -f body="<!-- ext-contribution-slack-sent --> |
| 444 | + Slack notification sent to #explorer-ext-contributions for external review. |
| 445 | + To re-send, delete this comment and re-add the \`ext-contribution\` label." |
| 446 | +
|
299 | 447 | check-member: |
300 | 448 | if: | |
301 | 449 | github.event.issue.pull_request != null && |
|
0 commit comments