Implement UpdateProgress control #28
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Squad Label Enforce | |
| on: | |
| issues: | |
| types: [labeled] | |
| permissions: | |
| issues: write | |
| contents: read | |
| jobs: | |
| enforce: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Enforce mutual exclusivity | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const issue = context.payload.issue; | |
| const appliedLabel = context.payload.label.name; | |
| // Namespaces with mutual exclusivity rules | |
| const EXCLUSIVE_PREFIXES = ['go:', 'release:', 'type:', 'priority:']; | |
| // Skip if not a managed namespace label | |
| if (!EXCLUSIVE_PREFIXES.some(p => appliedLabel.startsWith(p))) { | |
| core.info(`Label ${appliedLabel} is not in a managed namespace — skipping`); | |
| return; | |
| } | |
| const allLabels = issue.labels.map(l => l.name); | |
| // Handle go: namespace (mutual exclusivity) | |
| if (appliedLabel.startsWith('go:')) { | |
| const otherGoLabels = allLabels.filter(l => | |
| l.startsWith('go:') && l !== appliedLabel | |
| ); | |
| if (otherGoLabels.length > 0) { | |
| // Remove conflicting go: labels | |
| for (const label of otherGoLabels) { | |
| await github.rest.issues.removeLabel({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: issue.number, | |
| name: label | |
| }); | |
| core.info(`Removed conflicting label: ${label}`); | |
| } | |
| // Post update comment | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: issue.number, | |
| body: `🏷️ Triage verdict updated → \`${appliedLabel}\`` | |
| }); | |
| } | |
| // Auto-apply release:backlog if go:yes and no release target | |
| if (appliedLabel === 'go:yes') { | |
| const hasReleaseLabel = allLabels.some(l => l.startsWith('release:')); | |
| if (!hasReleaseLabel) { | |
| await github.rest.issues.addLabels({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: issue.number, | |
| labels: ['release:backlog'] | |
| }); | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: issue.number, | |
| body: `📋 Marked as \`release:backlog\` — assign a release target when ready.` | |
| }); | |
| core.info('Applied release:backlog for go:yes issue'); | |
| } | |
| } | |
| // Remove release: labels if go:no | |
| if (appliedLabel === 'go:no') { | |
| const releaseLabels = allLabels.filter(l => l.startsWith('release:')); | |
| if (releaseLabels.length > 0) { | |
| for (const label of releaseLabels) { | |
| await github.rest.issues.removeLabel({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: issue.number, | |
| name: label | |
| }); | |
| core.info(`Removed release label from go:no issue: ${label}`); | |
| } | |
| } | |
| } | |
| } | |
| // Handle release: namespace (mutual exclusivity) | |
| if (appliedLabel.startsWith('release:')) { | |
| const otherReleaseLabels = allLabels.filter(l => | |
| l.startsWith('release:') && l !== appliedLabel | |
| ); | |
| if (otherReleaseLabels.length > 0) { | |
| // Remove conflicting release: labels | |
| for (const label of otherReleaseLabels) { | |
| await github.rest.issues.removeLabel({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: issue.number, | |
| name: label | |
| }); | |
| core.info(`Removed conflicting label: ${label}`); | |
| } | |
| // Post update comment | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: issue.number, | |
| body: `🏷️ Release target updated → \`${appliedLabel}\`` | |
| }); | |
| } | |
| } | |
| // Handle type: namespace (mutual exclusivity) | |
| if (appliedLabel.startsWith('type:')) { | |
| const otherTypeLabels = allLabels.filter(l => | |
| l.startsWith('type:') && l !== appliedLabel | |
| ); | |
| if (otherTypeLabels.length > 0) { | |
| for (const label of otherTypeLabels) { | |
| await github.rest.issues.removeLabel({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: issue.number, | |
| name: label | |
| }); | |
| core.info(`Removed conflicting label: ${label}`); | |
| } | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: issue.number, | |
| body: `🏷️ Issue type updated → \`${appliedLabel}\`` | |
| }); | |
| } | |
| } | |
| // Handle priority: namespace (mutual exclusivity) | |
| if (appliedLabel.startsWith('priority:')) { | |
| const otherPriorityLabels = allLabels.filter(l => | |
| l.startsWith('priority:') && l !== appliedLabel | |
| ); | |
| if (otherPriorityLabels.length > 0) { | |
| for (const label of otherPriorityLabels) { | |
| await github.rest.issues.removeLabel({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: issue.number, | |
| name: label | |
| }); | |
| core.info(`Removed conflicting label: ${label}`); | |
| } | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: issue.number, | |
| body: `🏷️ Priority updated → \`${appliedLabel}\`` | |
| }); | |
| } | |
| } | |
| core.info(`Label enforcement complete for ${appliedLabel}`); |