summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhathach <[email protected]>2026-06-04 12:16:13 +0700
committerhathach <[email protected]>2026-06-04 12:16:13 +0700
commit824a2d6d8567deb163ecae79bf7cccfa59159c6a (patch)
tree957e73fe69ac6305bc023fe917f277707f9b74f4
parent35d67a28403fc12970aa39866ff1c24ab41698e6 (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.yml135
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
+ });
+ }
}