From ccd1854c66f6b095a53c373ffdab5e905dd9aad2 Mon Sep 17 00:00:00 2001 From: Coco Sheng Date: Thu, 14 May 2026 17:15:49 -0400 Subject: [PATCH] temp: limit 2 for ci test --- .github/scripts/apply-issue-labels.cjs | 89 ++++++++++--------- .github/scripts/find-conflicting-labels.cjs | 60 ------------- .github/scripts/gemini-lifecycle-manager.cjs | 3 +- .../gemini-automated-issue-dedup.yml | 1 + .../gemini-scheduled-issue-triage.yml | 36 +++++--- 5 files changed, 75 insertions(+), 114 deletions(-) delete mode 100644 .github/scripts/find-conflicting-labels.cjs diff --git a/.github/scripts/apply-issue-labels.cjs b/.github/scripts/apply-issue-labels.cjs index 8e25d9d782..017309ec41 100644 --- a/.github/scripts/apply-issue-labels.cjs +++ b/.github/scripts/apply-issue-labels.cjs @@ -87,6 +87,23 @@ module.exports = async ({ github, context, core }) => { let labelsToAdd = entry.labels_to_add || []; let labelsToRemove = entry.labels_to_remove || []; + let existingLabels = []; + + // Fetch existing labels early + try { + const { data: issueData } = await github.rest.issues.get({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issueNumber, + }); + existingLabels = issueData.labels.map((l) => + typeof l === 'string' ? l : l.name, + ); + } catch (e) { + core.warning( + `Failed to fetch existing labels for #${issueNumber}: ${e.message}`, + ); + } // Programmatic Priority Downgrade Logic if (labelsToAdd.includes('status/need-information')) { @@ -110,7 +127,10 @@ module.exports = async ({ github, context, core }) => { labelsToRemove.push('status/need-triage'); - if (labelsToAdd.includes('status/manual-triage')) { + if ( + labelsToAdd.includes('status/manual-triage') || + existingLabels.includes('status/manual-triage') + ) { // If the AI flagged it for manual triage, remove bot-triaged if it exists labelsToRemove.push('status/bot-triaged'); // Ensure we don't accidentally try to add bot-triaged if the AI returned it @@ -125,48 +145,24 @@ module.exports = async ({ github, context, core }) => { labelsToRemove = [...new Set(labelsToRemove)]; // Fetch existing labels to auto-resolve conflicts - try { - const { data: issueData } = await github.rest.issues.get({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: issueNumber, - }); - const existingLabels = issueData.labels.map((l) => - typeof l === 'string' ? l : l.name, + const hasNewArea = labelsToAdd.some((l) => l.startsWith('area/')); + if (hasNewArea) { + const existingAreas = existingLabels.filter((l) => l.startsWith('area/')); + labelsToRemove.push(...existingAreas); + } + + const hasNewPriority = labelsToAdd.some((l) => l.startsWith('priority/')); + if (hasNewPriority) { + const existingPriorities = existingLabels.filter((l) => + l.startsWith('priority/'), ); + labelsToRemove.push(...existingPriorities); + } - const hasNewArea = labelsToAdd.some((l) => l.startsWith('area/')); - if (hasNewArea) { - const existingAreas = existingLabels.filter((l) => - l.startsWith('area/'), - ); - labelsToRemove.push(...existingAreas); - } - - const hasNewPriority = labelsToAdd.some((l) => l.startsWith('priority/')); - if (hasNewPriority) { - const existingPriorities = existingLabels.filter((l) => - l.startsWith('priority/'), - ); - labelsToRemove.push(...existingPriorities); - } - - const hasNewKind = labelsToAdd.some((l) => l.startsWith('kind/')); - if (hasNewKind) { - const existingKinds = existingLabels.filter((l) => - l.startsWith('kind/'), - ); - labelsToRemove.push(...existingKinds); - } - - // Re-deduplicate and filter out labels we are trying to add - labelsToRemove = [...new Set(labelsToRemove)].filter( - (l) => !labelsToAdd.includes(l), - ); - } catch (e) { - core.warning( - `Failed to fetch existing labels for #${issueNumber}: ${e.message}`, - ); + const hasNewKind = labelsToAdd.some((l) => l.startsWith('kind/')); + if (hasNewKind) { + const existingKinds = existingLabels.filter((l) => l.startsWith('kind/')); + labelsToRemove.push(...existingKinds); } // Enforce mutually exclusive area labels @@ -195,6 +191,13 @@ module.exports = async ({ github, context, core }) => { ); } + // Re-deduplicate and filter out labels we are trying to add, + // and filter out labels that are already present or absent to avoid unnecessary API calls + labelsToRemove = [...new Set(labelsToRemove)].filter( + (l) => !labelsToAdd.includes(l) && existingLabels.includes(l), + ); + labelsToAdd = labelsToAdd.filter((l) => !existingLabels.includes(l)); + if (labelsToAdd.length > 0) { await github.rest.issues.addLabels({ owner: context.repo.owner, @@ -235,7 +238,9 @@ module.exports = async ({ github, context, core }) => { // - Silence standard triage (Area/Kind/Priority) to avoid spam. // - Only comment if status/need-information is added (to explain what is missing). // - Only comment if effort_analysis is present (deep technical dive). - const needsInfoAdded = labelsToAdd.includes('status/need-information'); + const needsInfoAdded = + labelsToAdd.includes('status/need-information') && + !existingLabels.includes('status/need-information'); const hasEffortAnalysis = !!entry.effort_analysis; if (needsInfoAdded || hasEffortAnalysis) { diff --git a/.github/scripts/find-conflicting-labels.cjs b/.github/scripts/find-conflicting-labels.cjs deleted file mode 100644 index 35b5e64e5a..0000000000 --- a/.github/scripts/find-conflicting-labels.cjs +++ /dev/null @@ -1,60 +0,0 @@ -/** - * @license - * Copyright 2026 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -const fs = require('node:fs'); - -module.exports = async ({ github, context, core }) => { - core.info('Fetching open issues to check for conflicting labels...'); - - const issues = await github.paginate(github.rest.issues.listForRepo, { - owner: context.repo.owner, - repo: context.repo.repo, - state: 'open', - per_page: 100, - }); - - const conflictingLabelIssues = []; - - for (const issue of issues) { - if (issue.pull_request) continue; - - const areaLabels = issue.labels - .filter((l) => l.name && l.name.startsWith('area/')) - .map((l) => l.name); - - const priorityLabels = issue.labels - .filter((l) => l.name && l.name.startsWith('priority/')) - .map((l) => l.name); - - if (areaLabels.length > 1 || priorityLabels.length > 1) { - let message = `Issue #${issue.number} has conflicting labels:`; - if (areaLabels.length > 1) - message += ` multiple areas (${areaLabels.join(', ')}).`; - if (priorityLabels.length > 1) - message += ` multiple priorities (${priorityLabels.join(', ')}).`; - - core.info(message); - - conflictingLabelIssues.push({ - number: issue.number, - title: issue.title, - body: issue.body || '', - }); - } - } - - // Limit to 50 to avoid overwhelming the AI in a single run - const issuesToProcess = conflictingLabelIssues.slice(0, 50); - - fs.writeFileSync( - 'conflicting_labels_issues.json', - JSON.stringify(issuesToProcess, null, 2), - ); - - core.info( - `Found ${conflictingLabelIssues.length} issues with conflicting labels. Wrote ${issuesToProcess.length} to conflicting_labels_issues.json`, - ); -}; diff --git a/.github/scripts/gemini-lifecycle-manager.cjs b/.github/scripts/gemini-lifecycle-manager.cjs index d1d04e0b19..024e6815d8 100644 --- a/.github/scripts/gemini-lifecycle-manager.cjs +++ b/.github/scripts/gemini-lifecycle-manager.cjs @@ -79,7 +79,7 @@ module.exports = async ({ github, context, core }) => { async function processItems(query, callback) { core.info(`Searching: ${query}`); try { - const items = await github.paginate( + let items = await github.paginate( github.rest.search.issuesAndPullRequests, { q: query, @@ -88,6 +88,7 @@ module.exports = async ({ github, context, core }) => { order: 'asc', }, ); + items = items.slice(0, 2); core.info(`Found ${items.length} items.`); for (const item of items) { try { diff --git a/.github/workflows/gemini-automated-issue-dedup.yml b/.github/workflows/gemini-automated-issue-dedup.yml index 27bc9f27fa..5fa274d7e7 100644 --- a/.github/workflows/gemini-automated-issue-dedup.yml +++ b/.github/workflows/gemini-automated-issue-dedup.yml @@ -68,6 +68,7 @@ jobs: ISSUE_NUMBER: '${{ github.event.issue.number }}' REPOSITORY: '${{ github.repository }}' FIRESTORE_PROJECT: '${{ vars.FIRESTORE_PROJECT }}' + GEMINI_CLI_TRUST_WORKSPACE: 'true' with: gcp_workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}' gcp_project_id: '${{ vars.GOOGLE_CLOUD_PROJECT }}' diff --git a/.github/workflows/gemini-scheduled-issue-triage.yml b/.github/workflows/gemini-scheduled-issue-triage.yml index cb212db7ed..253560bec9 100644 --- a/.github/workflows/gemini-scheduled-issue-triage.yml +++ b/.github/workflows/gemini-scheduled-issue-triage.yml @@ -62,12 +62,20 @@ jobs: - name: 'Find Issues with Conflicting Labels' if: |- ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} - uses: 'actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea' - with: - github-token: '${{ steps.generate_token.outputs.token }}' - script: |- - const findConflictingLabels = require('./.github/scripts/find-conflicting-labels.cjs'); - await findConflictingLabels({ github, context, core }); + env: + GITHUB_TOKEN: '${{ steps.generate_token.outputs.token }}' + GITHUB_REPOSITORY: '${{ github.repository }}' + run: |- + set -euo pipefail + echo '๐Ÿ” Fetching open issues to find conflicts...' + # Fetch up to 2000 open issues in one quick GraphQL-backed query + gh issue list --repo "${GITHUB_REPOSITORY}" --state open --limit 2000 --json number,title,body,labels > all_open_issues.json + + echo '๐Ÿงน Filtering issues with multiple area/ or priority/ labels...' + jq -c '[ .[] | select( (.labels | map(select(.name | startswith("area/"))) | length) > 1 or (.labels | map(select(.name | startswith("priority/"))) | length) > 1 ) ] | .[0:50]' all_open_issues.json > conflicting_labels_issues.json + + CONFLICT_COUNT=$(jq 'length' conflicting_labels_issues.json) + echo "Found ${CONFLICT_COUNT} issues with conflicting labels (capped at 50 for processing)." - name: 'Find untriaged issues' if: |- @@ -93,7 +101,7 @@ jobs: echo '๐Ÿ“ Finding issues missing effort labels...' gh issue list --repo "${GITHUB_REPOSITORY}" \ - --search 'is:open is:issue -label:effort/small -label:effort/medium -label:effort/large label:area/core,area/extensions,area/site,area/non-interactive' --limit 5 --json number,title,body,labels > no_effort_issues.json + --search 'is:open is:issue -label:effort/small -label:effort/medium -label:effort/large label:area/core,area/extensions,area/site,area/non-interactive' --limit 20 --json number,title,body,labels > no_effort_issues.json echo '๐Ÿ”„ Merging and deduplicating standard triage issues...' if [ ! -f conflicting_labels_issues.json ]; then echo "[]" > conflicting_labels_issues.json; fi @@ -158,6 +166,7 @@ jobs: GEMINI_CLI_TRUST_WORKSPACE: 'true' GEMINI_EXP: 'gemini_exp.json' GEMINI_STRICT_TELEMETRY_LIMITS: 'true' + GEMINI_MODEL: 'gemini-3-flash-preview' with: gcp_workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}' gcp_project_id: '${{ vars.GOOGLE_CLOUD_PROJECT }}' @@ -174,7 +183,7 @@ jobs: "read_file" ], "telemetry": { - "enabled": true, + "enabled": false, "target": "gcp" } } @@ -232,6 +241,7 @@ jobs: - Identify only one kind/ label (Do not apply kind/duplicate or kind/parent-issue) - Identify exactly ONE priority/ label. Do NOT assign multiple priority/ labels to a single issue. - **Do not manually downgrade the priority.** Always assign the true priority based on the guidelines. The system will handle downgrades programmatically if information is missing. + - **NEVER mention label names, label removals, or label additions in your `explanation`.** The explanation must be purely written for the user (e.g., "Please provide your CLI version.") without exposing internal triage mechanics (e.g., do NOT say "Removing area/unknown to leave only area/core"). Categorization Guidelines (Priority): P0 - Urgent Blocking Issues: @@ -277,6 +287,7 @@ jobs: GEMINI_CLI_TRUST_WORKSPACE: 'true' GEMINI_EXP: 'gemini_exp.json' GEMINI_STRICT_TELEMETRY_LIMITS: 'true' + GEMINI_MODEL: 'gemini-3-flash-preview' with: gcp_workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}' gcp_project_id: '${{ vars.GOOGLE_CLOUD_PROJECT }}' @@ -295,7 +306,7 @@ jobs: "read_file" ], "telemetry": { - "enabled": true, + "enabled": false, "target": "gcp" } } @@ -430,9 +441,12 @@ jobs: GITHUB_REPOSITORY: '${{ github.repository }}' run: |- set -euo pipefail - echo '๐Ÿงน Finding issues that have both bot-triaged and need-triage labels...' + echo '๐Ÿงน Finding issues that have conflicting status labels...' gh issue list --repo "${GITHUB_REPOSITORY}" \ - --search 'is:open is:issue label:status/bot-triaged label:status/need-triage' --limit 50 --json number > issues_to_cleanup.json + --search 'is:open is:issue label:status/bot-triaged label:status/need-triage' --limit 50 --json number > cleanup_1.json + gh issue list --repo "${GITHUB_REPOSITORY}" \ + --search 'is:open is:issue label:status/bot-triaged label:status/manual-triage' --limit 50 --json number > cleanup_2.json + jq -c -s 'add | unique_by(.number)' cleanup_1.json cleanup_2.json > issues_to_cleanup.json - name: 'Clean Up Triage Labels' if: |-