diff --git a/.github/workflows/issue_triage.yml b/.github/workflows/issue_triage.yml new file mode 100644 index 00000000000..f2cc394a19d --- /dev/null +++ b/.github/workflows/issue_triage.yml @@ -0,0 +1,71 @@ +name: Issue Triage and Management + +on: + issues: + types: [opened, labeled, assigned] + +permissions: + issues: write + +jobs: + triage-on-issue-open: + runs-on: ubuntu-latest + if: github.event.sender.login != 'github-actions' + steps: + - name: Reply to Issue + if: ${{ github.event.action == 'opened' }} + uses: peter-evans/create-or-update-comment@v4 + with: + issue-number: ${{ github.event.issue.number }} + body: | + Thanks for filing the issue! We’ll review it shortly and route it to the correct team. + + - name: Check Labels for Proper Triaging + id: check-labels + uses: actions/github-script@v6 + with: + script: | + const issue = await github.rest.issues.get({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number + }); + const labels = issue.data.labels.map(label => label.name); + const requiredLabels = { + types: ['bug', 'enhancement', 'good first issue'], + impacts: ['Impact: High', 'Impact: Medium', 'Impact: Low'], + work: ['Work: High', 'Work: Medium', 'Work: Low'], + }; + const hasTypeLabel = labels.some(label => requiredLabels.types.includes(label)); + const hasImpactLabel = labels.some(label => requiredLabels.impacts.includes(label)); + const hasWorkLabel = labels.some(label => requiredLabels.work.includes(label)); + const needsTriage = !(hasTypeLabel && hasImpactLabel && hasWorkLabel); + core.setOutput('needs-triage', needsTriage); + + - name: Manage Needs Triage Label + uses: actions/github-script@v6 + with: + script: | + const needsTriage = '${{ steps.check-labels.outputs.needs-triage }}' === 'true'; + if (needsTriage) { + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + labels: ['needs-triage'] + }); + } else { + try { + await github.rest.issues.removeLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + name: 'needs-triage' + }); + } catch (error) { + if (error.status !== 404) { + throw error; + } + } + } + diff --git a/.github/workflows/project_assigned_verify.yml b/.github/workflows/project_assigned_verify.yml new file mode 100644 index 00000000000..3d86d07093d --- /dev/null +++ b/.github/workflows/project_assigned_verify.yml @@ -0,0 +1,67 @@ +name: Verify Project Assignment + +on: + issues: + types: [labeled] + +permissions: + issues: write + +jobs: + verify-project-assignment: + runs-on: ubuntu-latest + if: github.event.sender.login != 'github-actions' + steps: + - name: Check if Label is an Impact Label + id: check-impact-label + run: | + if [[ "${{ github.event.label.name }}" == "Impact: High" ]] || \ + [[ "${{ github.event.label.name }}" == "Impact: Medium" ]] || \ + [[ "${{ github.event.label.name }}" == "Impact: Low" ]]; then + echo "impact_label=true" >> $GITHUB_ENV + else + echo "impact_label=false" >> $GITHUB_ENV + fi + + - name: Verify Project Assignment + if: env.impact_label == 'true' + uses: actions/github-script@v6 + with: + script: | + const issueNumber = context.issue.number; + + # Fetch all open projects in the repository + const projects = await github.rest.projects.listForRepo({ + owner: context.repo.owner, + repo: context.repo.repo, + }); + + # Filter to get only open projects + const assignedProjects = projects.data.filter(project => project.state === 'open'); + + if (assignedProjects.length !== 1) { + console.warn(`Issue must be assigned to exactly one open project. Found: ${assignedProjects.length}`); + + # Add a comment to notify about incorrect project assignment + const existingComments = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issueNumber, + }); + + const commentAlreadyExists = existingComments.data.some(comment => + comment.body.includes('Gentle Reminder: This issue must be assigned to exactly one open project') + ); + + if (!commentAlreadyExists) { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issueNumber, + body: `Gentle Reminder: This issue must be assigned to exactly one open project. Currently, ${assignedProjects.length} projects are assigned. Thanks.`, + }); + } + } else { + console.log(`Valid project assignment: ${assignedProjects[0].name}`); + } +