summaryrefslogtreecommitdiff
path: root/.github/workflows/labeler.yml
diff options
context:
space:
mode:
Diffstat (limited to '.github/workflows/labeler.yml')
-rw-r--r--.github/workflows/labeler.yml159
1 files changed, 134 insertions, 25 deletions
diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml
index c3cc59d0d..fe09413f1 100644
--- a/.github/workflows/labeler.yml
+++ b/.github/workflows/labeler.yml
@@ -4,23 +4,29 @@ on:
issues:
types: [opened]
pull_request_target:
- types: [opened]
+ types: [opened, synchronize, reopened]
+ discussion:
+ types: [created]
jobs:
label-priority:
+ # Author-based priority labels: only on issue/PR/discussion creation, not on PR updates.
+ if: github.event_name != 'pull_request_target' || github.event.action == 'opened'
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
+ discussions: write
steps:
- - name: Label New Issue or PR
- uses: actions/github-script@v7
+ - name: Label New Issue, PR or Discussion
+ uses: actions/github-script@v8
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 +34,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');
}
- } catch (error) {
- console.log('Not an Adafruit member');
}
- // Check if a contributor
- if (label == '') {
+ // 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);
+ }
+ }
+
+ // 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 +122,61 @@ 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
+ });
+ }
}
+
+ # Path-based Port labels: attach "Port <ip>" when a PR touches the matching
+ # dcd/hcd driver under src/portable/. Mapping lives in .github/labeler.yml.
+ label-port:
+ if: github.event_name == 'pull_request_target'
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ pull-requests: write
+ issues: write # allow auto-creating a Port label that doesn't exist yet
+ steps:
+ - uses: actions/labeler@v5
+ with:
+ configuration-path: .github/labeler.yml
+ # sync-labels so a Port label is removed once a PR no longer touches
+ # that driver (job reruns on synchronize). Only labels listed in
+ # labeler.yml are managed, so author-based Prio/Sponsor labels are untouched.
+ sync-labels: true