diff options
| author | hathach <[email protected]> | 2026-06-04 12:16:13 +0700 |
|---|---|---|
| committer | hathach <[email protected]> | 2026-06-04 12:16:13 +0700 |
| commit | 824a2d6d8567deb163ecae79bf7cccfa59159c6a (patch) | |
| tree | 957e73fe69ac6305bc023fe917f277707f9b74f4 | |
| parent | 35d67a28403fc12970aa39866ff1c24ab41698e6 (diff) | |
ci(labeler): add sponsor/Adafruit tiers, owner skip, and discussion support
- rename priority labels usage to Prio / Prio Top
- label Adafruit members (Adafruit + Sponsor + Prio Top) and public
GitHub sponsors by tier; contributors get Prio
- skip sponsor/Adafruit perks for the maintainer's own issues/PRs
- support discussions via the GraphQL addLabelsToLabelable mutation
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
| -rw-r--r-- | .github/workflows/labeler.yml | 135 |
1 files changed, 112 insertions, 23 deletions
diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index c3cc59d0d..1fdd24bf8 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -5,6 +5,8 @@ on: types: [opened] pull_request_target: types: [opened] + discussion: + types: [created] jobs: label-priority: @@ -12,15 +14,17 @@ jobs: permissions: issues: write pull-requests: write + discussions: write steps: - - name: Label New Issue or PR + - name: Label New Issue, PR or Discussion uses: actions/github-script@v7 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | - let label = ''; + let labels = []; let username = ''; let issueOrPrNumber = 0; + let discussionNodeId = ''; if (context.eventName === 'issues') { username = context.payload.issue.user.login; @@ -28,25 +32,85 @@ jobs: } else if (context.eventName === 'pull_request_target') { username = context.payload.pull_request.user.login; issueOrPrNumber = context.payload.pull_request.number; + } else if (context.eventName === 'discussion') { + username = context.payload.discussion.user.login; + discussionNodeId = context.payload.discussion.node_id; } - // Check if an Adafruit member - try { - const adafruitResponse = await github.rest.orgs.checkMembershipForUser({ - org: 'adafruit', - username: username - }); + // Maintainer is an Adafruit member; skip the Adafruit perks for their own + // issues/PRs and treat them as a plain contributor (Prio only). + const isOwner = username.toLowerCase() === 'hathach'; - if (adafruitResponse.status === 204) { - console.log('Adafruit Member'); - label = 'Prio Urgent'; + // Check if an Adafruit member: Adafruit + Sponsor + top priority + if (!isOwner) { + try { + const adafruitResponse = await github.rest.orgs.checkMembershipForUser({ + org: 'adafruit', + username: username + }); + + if (adafruitResponse.status === 204) { + console.log('Adafruit Member'); + labels = ['Adafruit', 'Sponsor', 'Prio Top']; + } + } catch (error) { + console.log('Not an Adafruit member'); + } + } + + // Check if a public GitHub Sponsor of the repo owner. + // Word ($32) tier and up get triage priority; DWORD/QWORD ($128+) go to the top. + // Private sponsorships are not visible to GITHUB_TOKEN, so only public sponsors are detected. + if (labels.length === 0) { + try { + const result = await github.graphql(` + query($sponsorable: String!, $sponsor: String!) { + user(login: $sponsorable) { + isSponsoredBy(accountLogin: $sponsor) + sponsorshipsAsMaintainer(includePrivate: false, first: 100) { + nodes { + sponsorEntity { + ... on User { login } + ... on Organization { login } + } + tier { monthlyPriceInDollars } + } + } + } + }`, { sponsorable: context.repo.owner, sponsor: username }); + + const owner = result.user; + if (owner && owner.isSponsoredBy) { + let monthly = 0; + const nodes = (owner.sponsorshipsAsMaintainer && owner.sponsorshipsAsMaintainer.nodes) || []; + for (const node of nodes) { + const login = node.sponsorEntity && node.sponsorEntity.login; + if (login && login.toLowerCase() === username.toLowerCase()) { + monthly = (node.tier && node.tier.monthlyPriceInDollars) || 0; + break; + } + } + + if (monthly >= 128) { + console.log('Sponsor (DWORD/QWORD tier)'); + labels = ['Sponsor', 'Prio Top']; + } else if (monthly >= 32) { + console.log('Sponsor (Word tier)'); + labels = ['Sponsor', 'Prio']; + } else { + console.log('Sponsor (below Word tier or tier not visible)'); + labels = ['Sponsor']; + } + } else { + console.log('Not a public sponsor'); + } + } catch (error) { + console.log('Sponsor lookup failed: ' + error.message); } - } catch (error) { - console.log('Not an Adafruit member'); } - // Check if a contributor - if (label == '') { + // Check if a contributor: prioritized in triage queue + if (labels.length === 0) { try { const collaboratorResponse = await github.rest.repos.checkCollaborator({ owner: context.repo.owner, @@ -56,18 +120,43 @@ jobs: if (collaboratorResponse.status === 204) { console.log('Contributor'); - label = 'Prio Higher'; + labels = ['Prio']; } } catch (error) { console.log('Not a contributor'); } } - if (label !== '') { - await github.rest.issues.addLabels({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: issueOrPrNumber, - labels: [label] - }); + if (labels.length !== 0) { + if (context.eventName === 'discussion') { + // Discussions are not covered by the REST issues API; resolve the label + // names to node IDs and attach them with the GraphQL labelable mutation. + const labelIds = []; + for (const name of labels) { + const res = await github.graphql(` + query($owner: String!, $repo: String!, $name: String!) { + repository(owner: $owner, name: $repo) { + label(name: $name) { id } + } + }`, { owner: context.repo.owner, repo: context.repo.repo, name: name }); + if (res.repository.label) { + labelIds.push(res.repository.label.id); + } + } + if (labelIds.length !== 0) { + await github.graphql(` + mutation($labelableId: ID!, $labelIds: [ID!]!) { + addLabelsToLabelable(input: { labelableId: $labelableId, labelIds: $labelIds }) { + clientMutationId + } + }`, { labelableId: discussionNodeId, labelIds: labelIds }); + } + } else { + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issueOrPrNumber, + labels: labels + }); + } } |
