name: '🏷️ Enforce Restricted Label Permissions' on: issues: types: - 'labeled' - 'unlabeled' jobs: enforce-label: # Run this job only when restricted labels are changed if: |- ${{ (github.event.label.name == 'help wanted' || github.event.label.name == 'status/need-triage') && (github.repository == 'google-gemini/gemini-cli' || github.repository == 'google-gemini/maintainers-gemini-cli') }} runs-on: 'ubuntu-latest' permissions: issues: 'write' steps: - name: 'Generate GitHub App Token' id: 'generate_token' env: APP_ID: '${{ secrets.APP_ID }}' if: |- ${{ env.APP_ID != '' }} uses: 'actions/create-github-app-token@a8d616148505b5069dccd32f177bb87d7f39123b' # ratchet:actions/create-github-app-token@v2 with: app-id: '${{ secrets.APP_ID }}' private-key: '${{ secrets.PRIVATE_KEY }}' - name: 'Check if user is in the maintainers team' uses: 'actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea' with: github-token: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}' script: |- const org = context.repo.owner; const username = context.payload.sender.login; const team_slug = 'gemini-cli-maintainers'; const action = context.payload.action; // 'labeled' or 'unlabeled' const labelName = context.payload.label.name; // Skip if the change was made by a bot to avoid infinite loops if (username === 'github-actions[bot]') { core.info('Change made by a bot. Skipping.'); return; } try { // This will succeed with a 204 status if the user is a member, // and fail with a 404 error if they are not. await github.rest.teams.getMembershipForUserInOrg ({ org, team_slug, username, }); core.info(`${username} is a member of the ${team_slug} team. No action needed.`); } catch (error) { // If the error is not 404, rethrow it to fail the action if (error.status !== 404) { throw error; } core.info(`${username} is not a member. Reverting '${action}' action for '${labelName}' label.`); if (action === 'labeled') { // 1. Remove the label if added by a non-maintainer await github.rest.issues.removeLabel ({ owner: org, repo: context.repo.repo, issue_number: context.issue.number, name: labelName }); // 2. Post a polite comment const comment = ` Hi @${username}, thank you for your interest in helping triage issues! The \`${labelName}\` label is reserved for project maintainers to apply. This helps us ensure that an issue is ready and properly vetted for community contribution. A maintainer will review this issue soon. Please see our [CONTRIBUTING.md](https://github.com/google-gemini/gemini-cli/blob/main/CONTRIBUTING.md) for more details on our labeling process. `.trim().replace(/^[ ]+/gm, ''); await github.rest.issues.createComment ({ owner: org, repo: context.repo.repo, issue_number: context.issue.number, body: comment }); } else if (action === 'unlabeled') { // 1. Add the label back if removed by a non-maintainer await github.rest.issues.addLabels ({ owner: org, repo: context.repo.repo, issue_number: context.issue.number, labels: [labelName] }); // 2. Post a polite comment const comment = ` Hi @${username}, it looks like the \`${labelName}\` label was removed. This label is managed by project maintainers. We've added it back to ensure the issue remains visible to potential contributors until a maintainer decides otherwise. Thank you for your understanding! `.trim().replace(/^[ ]+/gm, ''); await github.rest.issues.createComment ({ owner: org, repo: context.repo.repo, issue_number: context.issue.number, body: comment }); } }