mirror of
https://github.com/hathach/tinyusb.git
synced 2026-08-18 11:02:16 +00:00
Remove Sponsor Triage workflow (migrated to hathach/hathach) (#3675)
This personal automation now lives in the hathach/hathach repo alongside the other personal project-sync workflows; it has no place in the tinyusb library. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
165
.github/workflows/sponsor-triage.yml
vendored
165
.github/workflows/sponsor-triage.yml
vendored
@ -1,165 +0,0 @@
|
||||
name: Sponsor Triage
|
||||
|
||||
# Periodically add open issues and PRs opened by sponsors (public and private) to the private "Sponsor Triage" project board
|
||||
# Requires a PAT in secret SPONSOR_TOKEN with scopes:
|
||||
# - project (write project items / fields)
|
||||
# - read:org (search org issues, check Adafruit membership)
|
||||
# - read:user / sponsors (read own sponsorships incl. private)
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 */6 * * *' # every 6 hours
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: sponsor-triage
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
sync:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Sync sponsor issues to project board
|
||||
uses: actions/github-script@v8
|
||||
with:
|
||||
github-token: ${{ secrets.SPONSOR_TOKEN }}
|
||||
script: |
|
||||
const PROJECT_OWNER = 'hathach';
|
||||
const PROJECT_NUMBER = 3;
|
||||
// Where to look for sponsor-authored open issues.
|
||||
const SEARCH_SCOPES = ['org:adafruit', 'user:hathach'];
|
||||
|
||||
const tierFromMonthly = (m) => {
|
||||
if (m >= 512) return 'QWORD';
|
||||
if (m >= 128) return 'DWORD';
|
||||
if (m >= 32) return 'Word';
|
||||
if (m >= 8) return 'Byte';
|
||||
if (m >= 2) return 'Bit';
|
||||
return null;
|
||||
};
|
||||
|
||||
// --- 1. Resolve project id + field/option ids (by name, never hardcoded) ---
|
||||
const proj = await github.graphql(`
|
||||
query($owner: String!, $number: Int!) {
|
||||
user(login: $owner) {
|
||||
projectV2(number: $number) {
|
||||
id
|
||||
fields(first: 50) {
|
||||
nodes {
|
||||
... on ProjectV2SingleSelectField {
|
||||
id name options { id name }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`, { owner: PROJECT_OWNER, number: PROJECT_NUMBER });
|
||||
|
||||
const project = proj.user.projectV2;
|
||||
const fieldByName = {};
|
||||
for (const f of project.fields.nodes) {
|
||||
if (f && f.name) {
|
||||
fieldByName[f.name] = { id: f.id, options: {} };
|
||||
for (const o of (f.options || [])) fieldByName[f.name].options[o.name] = o.id;
|
||||
}
|
||||
}
|
||||
const tierField = fieldByName['Tier'];
|
||||
const visField = fieldByName['Visibility'];
|
||||
|
||||
// --- 2. Build sponsor map: loginLower -> { tier, visibility } ---
|
||||
const sponsors = new Map();
|
||||
|
||||
// 2a. GitHub Sponsors of the owner, including private ones.
|
||||
let after = null;
|
||||
for (let page = 0; page < 20; page++) {
|
||||
const res = await github.graphql(`
|
||||
query($owner: String!, $after: String) {
|
||||
user(login: $owner) {
|
||||
sponsorshipsAsMaintainer(includePrivate: true, first: 100, after: $after) {
|
||||
pageInfo { hasNextPage endCursor }
|
||||
nodes {
|
||||
privacyLevel
|
||||
tier { monthlyPriceInDollars }
|
||||
sponsorEntity {
|
||||
... on User { login }
|
||||
... on Organization { login }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`, { owner: PROJECT_OWNER, after });
|
||||
const conn = res.user.sponsorshipsAsMaintainer;
|
||||
for (const n of conn.nodes) {
|
||||
const login = n.sponsorEntity && n.sponsorEntity.login;
|
||||
if (!login) continue;
|
||||
const tier = tierFromMonthly((n.tier && n.tier.monthlyPriceInDollars) || 0);
|
||||
const visibility = n.privacyLevel === 'PRIVATE' ? 'Private' : 'Public';
|
||||
sponsors.set(login.toLowerCase(), { login, tier, visibility });
|
||||
}
|
||||
if (!conn.pageInfo.hasNextPage) break;
|
||||
after = conn.pageInfo.endCursor;
|
||||
}
|
||||
|
||||
core.info(`Resolved ${sponsors.size} sponsor account(s).`);
|
||||
if (sponsors.size === 0) return;
|
||||
|
||||
// 2b. Adafruit org members get the Adafruit tier regardless of $ amount.
|
||||
for (const s of sponsors.values()) {
|
||||
try {
|
||||
const m = await github.rest.orgs.checkMembershipForUser({ org: 'adafruit', username: s.login });
|
||||
if (m.status === 204) s.tier = 'Adafruit';
|
||||
} catch (e) { /* not an Adafruit member */ }
|
||||
}
|
||||
|
||||
// --- 3. Find each sponsor's open issues and PRs in the search scopes ---
|
||||
// (search type ISSUE returns both issues and pull requests)
|
||||
const found = new Map(); // contentId -> { tier, visibility }
|
||||
for (const s of sponsors.values()) {
|
||||
for (const scope of SEARCH_SCOPES) {
|
||||
const q = `${scope} is:open author:${s.login}`;
|
||||
try {
|
||||
const res = await github.graphql(`
|
||||
query($q: String!) {
|
||||
search(query: $q, type: ISSUE, first: 100) {
|
||||
nodes { ... on Issue { id } ... on PullRequest { id } }
|
||||
}
|
||||
}`, { q });
|
||||
for (const node of res.search.nodes) {
|
||||
if (node && node.id && !found.has(node.id)) {
|
||||
found.set(node.id, { tier: s.tier, visibility: s.visibility });
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
core.warning(`Search failed for one scope: ${e.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
core.info(`Found ${found.size} open sponsor issue(s) across scopes.`);
|
||||
|
||||
// --- 4. Add to board + set Tier / Visibility (idempotent) ---
|
||||
const setField = async (itemId, field, optionName) => {
|
||||
if (!field || !optionName) return;
|
||||
const optId = field.options[optionName];
|
||||
if (!optId) return;
|
||||
await github.graphql(`
|
||||
mutation($p: ID!, $i: ID!, $f: ID!, $o: String!) {
|
||||
updateProjectV2ItemFieldValue(input: {
|
||||
projectId: $p, itemId: $i, fieldId: $f, value: { singleSelectOptionId: $o }
|
||||
}) { projectV2Item { id } }
|
||||
}`, { p: project.id, i: itemId, f: field.id, o: optId });
|
||||
};
|
||||
|
||||
let added = 0;
|
||||
for (const [contentId, meta] of found) {
|
||||
const res = await github.graphql(`
|
||||
mutation($p: ID!, $c: ID!) {
|
||||
addProjectV2ItemById(input: { projectId: $p, contentId: $c }) {
|
||||
item { id }
|
||||
}
|
||||
}`, { p: project.id, c: contentId });
|
||||
const itemId = res.addProjectV2ItemById.item.id;
|
||||
await setField(itemId, tierField, meta.tier);
|
||||
await setField(itemId, visField, meta.visibility);
|
||||
added++;
|
||||
}
|
||||
core.info(`Synced ${added} item(s) to the board.`);
|
||||
Reference in New Issue
Block a user