diff --git a/.github/workflows/first-time-contributor.yml b/.github/workflows/contributor-guidance.yml similarity index 57% rename from .github/workflows/first-time-contributor.yml rename to .github/workflows/contributor-guidance.yml index f825cd77dc05..ca7fa1b2bbba 100644 --- a/.github/workflows/first-time-contributor.yml +++ b/.github/workflows/contributor-guidance.yml @@ -1,4 +1,4 @@ -name: Welcome first-time contributors +name: Contributor guidance on: pull_request_target: @@ -7,34 +7,50 @@ on: permissions: {} jobs: - first_time_contributor: - name: Is first-time contributor + contributor: + name: Resolve contributor status # GitHub can report first-time contributors as NONE in the event payload. + # npm-cli-bot and nodejs-github-bot report MEMBER and are filtered here. if: >- github.run_attempt == 1 && github.repository == 'nodejs/node' && + github.event.pull_request.user.login != 'dependabot[bot]' && (github.event.pull_request.author_association == 'FIRST_TIMER' || github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR' || github.event.pull_request.author_association == 'NONE') runs-on: ubuntu-slim - permissions: - pull-requests: read outputs: - eligible: >- - ${{ - github.event.pull_request.author_association != 'NONE' || - steps.recheck.outputs.eligible == 'true' - }} + is_first_time: ${{ steps.resolve.outputs.is_first_time }} + should_scan: ${{ steps.resolve.outputs.should_scan }} steps: - - name: Recheck contributor eligibility - id: recheck - if: github.event.pull_request.author_association == 'NONE' + - name: Check author association + id: resolve env: - GH_TOKEN: ${{ github.token }} + EVENT_ASSOCIATION: ${{ github.event.pull_request.author_association }} + GH_TOKEN: ${{ secrets.GH_USER_TOKEN }} NUMBER: ${{ github.event.pull_request.number }} run: | + echo "Author association from event: $EVENT_ASSOCIATION" + + case "$EVENT_ASSOCIATION" in + FIRST_TIMER|FIRST_TIME_CONTRIBUTOR) + echo 'is_first_time=true' >> "$GITHUB_OUTPUT" + echo 'should_scan=true' >> "$GITHUB_OUTPUT" + exit 0 + ;; + NONE) + ;; + *) + echo 'is_first_time=false' >> "$GITHUB_OUTPUT" + echo 'should_scan=false' >> "$GITHUB_OUTPUT" + exit 0 + ;; + esac + started_at=$SECONDS - for delay in 15 30 60 120; do + # TODO: Remove the retries once privileged API requests are confirmed + # to return the association immediately. + for delay in 0 15 30 60; do sleep "$delay" association=$(gh api "/repos/$GITHUB_REPOSITORY/pulls/$NUMBER" \ --jq '.author_association') @@ -43,60 +59,57 @@ jobs: case "$association" in FIRST_TIMER|FIRST_TIME_CONTRIBUTOR) - echo 'eligible=true' >> "$GITHUB_OUTPUT" + echo 'is_first_time=true' >> "$GITHUB_OUTPUT" + echo 'should_scan=true' >> "$GITHUB_OUTPUT" exit 0 ;; NONE) ;; *) - echo 'eligible=false' >> "$GITHUB_OUTPUT" + echo 'is_first_time=false' >> "$GITHUB_OUTPUT" + echo 'should_scan=true' >> "$GITHUB_OUTPUT" exit 0 ;; esac done - echo 'eligible=false' >> "$GITHUB_OUTPUT" + echo 'is_first_time=false' >> "$GITHUB_OUTPUT" + echo 'should_scan=false' >> "$GITHUB_OUTPUT" - agentscan: - needs: first_time_contributor - if: needs.first_time_contributor.outputs.eligible == 'true' + guidance: + name: Apply contributor guidance + needs: contributor + if: needs.contributor.outputs.should_scan == 'true' runs-on: ubuntu-slim permissions: contents: read - outputs: - scan_outcome: ${{ steps.scan.outcome }} - classification: ${{ steps.scan.outputs.classification }} - community_flagged: ${{ steps.scan.outputs['community-flagged'] }} + pull-requests: write steps: - name: Scan contributor activity - id: scan + id: agentscan # The welcome should still be posted if this advisory scan fails. continue-on-error: true - uses: MatteoGabriele/agentscan-action@98202262c925c508d4c1424b1dfbe17ee35b0c02 # v2.4.0 + uses: MatteoGabriele/agentscan-action@8112fb79b33fafb8506159df20129a34209ac410 # v2.5.0 with: github-token: ${{ github.token }} - mode: silent + mode: labels scan-pull-requests: true scan-issues: false auto-close: false honeypot: false - comment: - needs: - - first_time_contributor - - agentscan - if: needs.first_time_contributor.outputs.eligible == 'true' - runs-on: ubuntu-slim - permissions: - pull-requests: write - steps: - - name: Welcome first-time contributor + - name: Comment with contributor guidance env: + ADD_CAUTION: >- + ${{ + steps.agentscan.outcome == 'success' && + (steps.agentscan.outputs.classification == 'mixed' || + steps.agentscan.outputs.classification == 'automation' || + steps.agentscan.outputs['community-flagged'] == 'true') + }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + IS_FIRST_TIME: ${{ needs.contributor.outputs.is_first_time }} NUMBER: ${{ github.event.pull_request.number }} - AGENTSCAN_OUTCOME: ${{ needs.agentscan.outputs.scan_outcome }} - AGENTSCAN_CLASSIFICATION: ${{ needs.agentscan.outputs.classification }} - AGENTSCAN_COMMUNITY_FLAGGED: ${{ needs.agentscan.outputs.community_flagged }} WELCOME_MESSAGE: >2- Welcome to Node.js, and thank you for your first contribution! @@ -128,20 +141,15 @@ jobs: [automation policy](https://github.com/nodejs/node/blob/HEAD/CONTRIBUTING.md#automation-and-bots) for additional context. run: | - add_caution=false - if [[ "$AGENTSCAN_OUTCOME" == "success" ]]; then - case "$AGENTSCAN_CLASSIFICATION" in - mixed|automation) - add_caution=true - ;; - esac - if [[ "$AGENTSCAN_COMMUNITY_FLAGGED" == "true" ]]; then - add_caution=true - fi + if [[ "$IS_FIRST_TIME" == "true" && "$ADD_CAUTION" == "true" ]]; then + body="$WELCOME_MESSAGE"$'\n\n'"$CAUTION_MESSAGE" + elif [[ "$IS_FIRST_TIME" == "true" ]]; then + body="$WELCOME_MESSAGE" + elif [[ "$ADD_CAUTION" == "true" ]]; then + body="$CAUTION_MESSAGE" + else + exit 0 fi - if [[ "$add_caution" == "true" ]]; then - printf '%s\n\n%s\n' "$WELCOME_MESSAGE" "$CAUTION_MESSAGE" - else - printf '%s\n' "$WELCOME_MESSAGE" - fi | gh pr comment "$NUMBER" --repo "$GITHUB_REPOSITORY" --body-file - + printf '%s\n' "$body" | + gh pr comment "$NUMBER" --repo "$GITHUB_REPOSITORY" --body-file -