diff --git a/.github/workflows/contrib.yaml b/.github/workflows/contrib.yaml index bf81ece746..6e670f8332 100644 --- a/.github/workflows/contrib.yaml +++ b/.github/workflows/contrib.yaml @@ -30,16 +30,28 @@ jobs: if: >- ${{ github.event_name == 'pull_request_target' && - github.event.action == 'opened' && - github.event.pull_request.author_association != 'MEMBER' && - github.event.pull_request.author_association != 'COLLABORATOR' && - github.event.pull_request.author_association != 'OWNER' + github.event.action == 'opened' }} steps: + - name: Generate app token + id: app-token + uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1 + with: + app-id: ${{ vars.ORG_MEMBERSHIP_APP_ID }} + private-key: ${{ secrets.ORG_MEMBERSHIP_APP_PRIVATE_KEY }} - name: Add community label uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 + env: + APP_TOKEN: ${{ steps.app-token.outputs.token }} with: + # Default GITHUB_TOKEN handles label writes via the + # `github` object (needs pull-requests: write). The App + # token is scoped to members: read only and used via a + # separate Octokit client for the membership check. script: | + const { Octokit } = require("@octokit/rest") + const orgClient = new Octokit({ auth: process.env.APP_TOKEN }) + const params = { issue_number: context.issue.number, owner: context.repo.owner, @@ -52,10 +64,27 @@ jobs: return } - console.log( - 'Adding "community" label for author association "%s".', - context.payload.pull_request.author_association, - ) + // author_association can be unreliable: it returns + // CONTRIBUTOR instead of MEMBER when both apply, and + // returns NONE for members with private org visibility. + // Use the org membership API as the source of truth. + // See: https://github.com/actions/github-script/issues/643 + const author = context.payload.pull_request.user.login + try { + await orgClient.orgs.checkMembershipForUser({ + org: context.repo.owner, + username: author, + }) + console.log('Author "%s" is an org member, skipping.', author) + return + } catch (error) { + if (error.status !== 404 && error.status !== 302) { + throw error + } + } + + console.log('Adding "community" label for author "%s".', author) + // Uses the default GITHUB_TOKEN via the `github` object. await github.rest.issues.addLabels({ ...params, labels: ["community"],