mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-30 06:54:15 -07:00
fix(github): improve label-workstream-rollup efficiency with GraphQL (#17217)
This commit is contained in:
@@ -28,14 +28,27 @@ jobs:
|
|||||||
'https://github.com/google-gemini/gemini-cli/issues/17203'
|
'https://github.com/google-gemini/gemini-cli/issues/17203'
|
||||||
];
|
];
|
||||||
|
|
||||||
async function getIssueParent(owner, repo, number) {
|
// Single issue processing (for event triggers)
|
||||||
|
async function processSingleIssue(owner, repo, number) {
|
||||||
const query = `
|
const query = `
|
||||||
query($owner:String!, $repo:String!, $number:Int!) {
|
query($owner:String!, $repo:String!, $number:Int!) {
|
||||||
repository(owner:$owner, name:$repo) {
|
repository(owner:$owner, name:$repo) {
|
||||||
issue(number:$number) {
|
issue(number:$number) {
|
||||||
|
number
|
||||||
parent {
|
parent {
|
||||||
url
|
url
|
||||||
number
|
parent {
|
||||||
|
url
|
||||||
|
parent {
|
||||||
|
url
|
||||||
|
parent {
|
||||||
|
url
|
||||||
|
parent {
|
||||||
|
url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -43,73 +56,101 @@ jobs:
|
|||||||
`;
|
`;
|
||||||
try {
|
try {
|
||||||
const result = await github.graphql(query, { owner, repo, number });
|
const result = await github.graphql(query, { owner, repo, number });
|
||||||
return result.repository.issue.parent || null;
|
const issue = result.repository.issue;
|
||||||
|
checkAndLabel(issue, owner, repo);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Failed to fetch parent for #${number}:`, error);
|
console.error(`Failed to process issue #${number}:`, error);
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine which issues to process
|
// Bulk processing (for schedule/dispatch)
|
||||||
let issuesToProcess = [];
|
async function processAllOpenIssues(owner, repo) {
|
||||||
|
const query = `
|
||||||
|
query($owner:String!, $repo:String!, $cursor:String) {
|
||||||
|
repository(owner:$owner, name:$repo) {
|
||||||
|
issues(first: 100, states: OPEN, after: $cursor) {
|
||||||
|
pageInfo {
|
||||||
|
hasNextPage
|
||||||
|
endCursor
|
||||||
|
}
|
||||||
|
nodes {
|
||||||
|
number
|
||||||
|
parent {
|
||||||
|
url
|
||||||
|
parent {
|
||||||
|
url
|
||||||
|
parent {
|
||||||
|
url
|
||||||
|
parent {
|
||||||
|
url
|
||||||
|
parent {
|
||||||
|
url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
if (context.eventName === 'issues') {
|
let hasNextPage = true;
|
||||||
// Context payload for 'issues' event already has the issue object
|
let cursor = null;
|
||||||
issuesToProcess.push({
|
|
||||||
number: context.payload.issue.number,
|
while (hasNextPage) {
|
||||||
owner: context.repo.owner,
|
try {
|
||||||
repo: context.repo.repo
|
const result = await github.graphql(query, { owner, repo, cursor });
|
||||||
});
|
const issues = result.repository.issues.nodes;
|
||||||
} else {
|
|
||||||
// For schedule/dispatch, fetch open issues (lightweight list)
|
console.log(`Processing batch of ${issues.length} issues...`);
|
||||||
console.log(`Running for event: ${context.eventName}. Fetching open issues...`);
|
for (const issue of issues) {
|
||||||
const openIssues = await github.paginate(github.rest.issues.listForRepo, {
|
await checkAndLabel(issue, owner, repo);
|
||||||
owner: context.repo.owner,
|
}
|
||||||
repo: context.repo.repo,
|
|
||||||
state: 'open'
|
hasNextPage = result.repository.issues.pageInfo.hasNextPage;
|
||||||
});
|
cursor = result.repository.issues.pageInfo.endCursor;
|
||||||
issuesToProcess = openIssues.map(i => ({
|
} catch (error) {
|
||||||
number: i.number,
|
console.error('Failed to fetch issues batch:', error);
|
||||||
owner: context.repo.owner,
|
hasNextPage = false;
|
||||||
repo: context.repo.repo
|
}
|
||||||
}));
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`Processing ${issuesToProcess.length} issue(s)...`);
|
async function checkAndLabel(issue, owner, repo) {
|
||||||
|
if (!issue || !issue.parent) return;
|
||||||
|
|
||||||
for (const issue of issuesToProcess) {
|
let currentParent = issue.parent;
|
||||||
let currentNumber = issue.number;
|
|
||||||
let depth = 0;
|
|
||||||
const MAX_DEPTH = 5; // Safety limit for recursion
|
|
||||||
let matched = false;
|
|
||||||
let tracedParents = [];
|
let tracedParents = [];
|
||||||
|
let matched = false;
|
||||||
|
|
||||||
while (depth < MAX_DEPTH) {
|
while (currentParent) {
|
||||||
const parent = await getIssueParent(issue.owner, issue.repo, currentNumber);
|
tracedParents.push(currentParent.url);
|
||||||
|
|
||||||
if (!parent) {
|
if (allowedParentUrls.includes(currentParent.url)) {
|
||||||
break;
|
console.log(`SUCCESS: Issue #${issue.number} is a descendant of ${currentParent.url}. Trace: ${tracedParents.join(' -> ')}. Adding label.`);
|
||||||
}
|
|
||||||
|
|
||||||
tracedParents.push(parent.url);
|
|
||||||
|
|
||||||
if (allowedParentUrls.includes(parent.url)) {
|
|
||||||
console.log(`SUCCESS: Issue #${issue.number} is a descendant of ${parent.url}. Trace: ${tracedParents.join(' -> ')}. Adding label.`);
|
|
||||||
await github.rest.issues.addLabels({
|
await github.rest.issues.addLabels({
|
||||||
owner: issue.owner,
|
owner,
|
||||||
repo: issue.repo,
|
repo,
|
||||||
issue_number: issue.number,
|
issue_number: issue.number,
|
||||||
labels: [labelToAdd]
|
labels: [labelToAdd]
|
||||||
});
|
});
|
||||||
matched = true;
|
matched = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
currentParent = currentParent.parent;
|
||||||
currentNumber = parent.number;
|
|
||||||
depth++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!matched && context.eventName === 'issues') {
|
if (!matched && context.eventName === 'issues') {
|
||||||
console.log(`Issue #${issue.number} did not match any allowed workstreams after checking ${depth} levels. Trace: ${tracedParents.join(' -> ') || 'None'}.`);
|
console.log(`Issue #${issue.number} did not match any allowed workstreams. Trace: ${tracedParents.join(' -> ') || 'None'}.`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Main execution
|
||||||
|
if (context.eventName === 'issues') {
|
||||||
|
console.log(`Processing single issue #${context.payload.issue.number}...`);
|
||||||
|
await processSingleIssue(context.repo.owner, context.repo.repo, context.payload.issue.number);
|
||||||
|
} else {
|
||||||
|
console.log(`Running for event: ${context.eventName}. Processing all open issues...`);
|
||||||
|
await processAllOpenIssues(context.repo.owner, context.repo.repo);
|
||||||
|
|||||||
Reference in New Issue
Block a user