mirror of
https://github.com/github/awesome-copilot.git
synced 2026-05-04 14:15:55 +00:00
feat: add PR intent labeling workflow (#1604)
* feat: label PR intent Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * need a git repo * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
5
.github/workflows/contributor-check.yml
vendored
5
.github/workflows/contributor-check.yml
vendored
@@ -19,6 +19,11 @@ jobs:
|
||||
github.actor != 'github-actions[bot]' &&
|
||||
github.actor != 'copilot-swe-agent[bot]'
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
||||
with:
|
||||
|
||||
241
.github/workflows/label-pr-intent.yml
vendored
Normal file
241
.github/workflows/label-pr-intent.yml
vendored
Normal file
@@ -0,0 +1,241 @@
|
||||
name: Label PR Intent
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened, synchronize, reopened, edited, ready_for_review]
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: read
|
||||
|
||||
jobs:
|
||||
label-pr:
|
||||
runs-on: ubuntu-latest
|
||||
if: >-
|
||||
github.actor != 'dependabot[bot]' &&
|
||||
github.actor != 'github-actions[bot]'
|
||||
steps:
|
||||
- name: Apply intent labels
|
||||
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
|
||||
with:
|
||||
script: |
|
||||
const managedLabels = {
|
||||
'targets-main': {
|
||||
color: 'B60205',
|
||||
description: 'PR targets main instead of staged'
|
||||
},
|
||||
'branched-main': {
|
||||
color: 'D93F0B',
|
||||
description: 'PR appears to include plugin files materialized from main'
|
||||
},
|
||||
'skills': {
|
||||
color: '1D76DB',
|
||||
description: 'PR touches skills'
|
||||
},
|
||||
'plugin': {
|
||||
color: '5319E7',
|
||||
description: 'PR touches plugins'
|
||||
},
|
||||
'agent': {
|
||||
color: '0E8A16',
|
||||
description: 'PR touches agents'
|
||||
},
|
||||
'instructions': {
|
||||
color: 'FBCA04',
|
||||
description: 'PR touches instructions'
|
||||
},
|
||||
'new-submission': {
|
||||
color: '006B75',
|
||||
description: 'PR adds at least one new contribution'
|
||||
},
|
||||
'website-update': {
|
||||
color: '0052CC',
|
||||
description: 'PR touches website content or code'
|
||||
},
|
||||
'external-plugin': {
|
||||
color: 'FEF2C0',
|
||||
description: 'PR updates plugins/external.json'
|
||||
},
|
||||
'hooks': {
|
||||
color: 'C2E0C6',
|
||||
description: 'PR touches hooks'
|
||||
},
|
||||
'workflow': {
|
||||
color: 'BFD4F2',
|
||||
description: 'PR touches workflow automation'
|
||||
}
|
||||
};
|
||||
|
||||
const matchesAny = (filename, patterns) => patterns.some((pattern) => pattern.test(filename));
|
||||
|
||||
async function listAllFiles() {
|
||||
const files = [];
|
||||
let page = 1;
|
||||
|
||||
while (true) {
|
||||
const response = await github.rest.pulls.listFiles({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: context.issue.number,
|
||||
per_page: 100,
|
||||
page
|
||||
});
|
||||
|
||||
files.push(...response.data);
|
||||
|
||||
if (response.data.length < 100) {
|
||||
return files;
|
||||
}
|
||||
|
||||
page += 1;
|
||||
}
|
||||
}
|
||||
|
||||
async function ensureLabel(name, { color, description }) {
|
||||
try {
|
||||
await github.rest.issues.createLabel({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
name,
|
||||
color,
|
||||
description
|
||||
});
|
||||
} catch (error) {
|
||||
if (error.status !== 422) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const files = await listAllFiles();
|
||||
const filenames = files.map((file) => file.filename);
|
||||
|
||||
const patterns = {
|
||||
branchedMain: [
|
||||
/^plugins\/[^/]+\/(?:agents|commands|skills)\//
|
||||
],
|
||||
skills: [
|
||||
/^skills\//
|
||||
],
|
||||
plugin: [
|
||||
/^plugins\//
|
||||
],
|
||||
agent: [
|
||||
/^agents\/.+\.agent\.md$/
|
||||
],
|
||||
instructions: [
|
||||
/^instructions\/.+\.instructions\.md$/
|
||||
],
|
||||
websiteUpdate: [
|
||||
/^website\//
|
||||
],
|
||||
externalPlugin: [
|
||||
/^plugins\/external\.json$/
|
||||
],
|
||||
hooks: [
|
||||
/^hooks\//
|
||||
],
|
||||
workflow: [
|
||||
/^workflows\/.+\.md$/,
|
||||
/^\.github\/workflows\/.+\.(?:ya?ml|md)$/
|
||||
],
|
||||
newSubmission: [
|
||||
/^agents\/.+\.agent\.md$/,
|
||||
/^instructions\/.+\.instructions\.md$/,
|
||||
/^skills\/[^/]+\/SKILL\.md$/,
|
||||
/^hooks\/[^/]+\/(?:README\.md|hooks\.json)$/,
|
||||
/^plugins\/[^/]+\/\.github\/plugin\/plugin\.json$/,
|
||||
/^workflows\/.+\.md$/,
|
||||
/^\.github\/workflows\/.+\.(?:ya?ml|md)$/,
|
||||
/^website\//
|
||||
]
|
||||
};
|
||||
|
||||
const isBranchedMain = filenames.some((filename) => matchesAny(filename, patterns.branchedMain));
|
||||
const hasNewSubmission = files.some(
|
||||
(file) => file.status === 'added' && matchesAny(file.filename, patterns.newSubmission)
|
||||
);
|
||||
|
||||
const desiredLabels = new Set();
|
||||
|
||||
if (context.payload.pull_request.base.ref === 'main') {
|
||||
desiredLabels.add('targets-main');
|
||||
}
|
||||
|
||||
if (filenames.some((filename) => matchesAny(filename, patterns.externalPlugin))) {
|
||||
desiredLabels.add('external-plugin');
|
||||
}
|
||||
|
||||
if (isBranchedMain) {
|
||||
desiredLabels.add('branched-main');
|
||||
} else {
|
||||
if (filenames.some((filename) => matchesAny(filename, patterns.skills))) {
|
||||
desiredLabels.add('skills');
|
||||
}
|
||||
|
||||
if (filenames.some((filename) => matchesAny(filename, patterns.plugin))) {
|
||||
desiredLabels.add('plugin');
|
||||
}
|
||||
|
||||
if (filenames.some((filename) => matchesAny(filename, patterns.agent))) {
|
||||
desiredLabels.add('agent');
|
||||
}
|
||||
|
||||
if (filenames.some((filename) => matchesAny(filename, patterns.instructions))) {
|
||||
desiredLabels.add('instructions');
|
||||
}
|
||||
|
||||
if (filenames.some((filename) => matchesAny(filename, patterns.websiteUpdate))) {
|
||||
desiredLabels.add('website-update');
|
||||
}
|
||||
|
||||
if (filenames.some((filename) => matchesAny(filename, patterns.hooks))) {
|
||||
desiredLabels.add('hooks');
|
||||
}
|
||||
|
||||
if (filenames.some((filename) => matchesAny(filename, patterns.workflow))) {
|
||||
desiredLabels.add('workflow');
|
||||
}
|
||||
|
||||
if (hasNewSubmission) {
|
||||
desiredLabels.add('new-submission');
|
||||
}
|
||||
}
|
||||
|
||||
await Promise.all(
|
||||
Object.entries(managedLabels).map(([name, config]) => ensureLabel(name, config))
|
||||
);
|
||||
|
||||
const currentLabels = await github.paginate(github.rest.issues.listLabelsOnIssue, {
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.issue.number,
|
||||
per_page: 100
|
||||
});
|
||||
|
||||
const currentManagedLabels = currentLabels
|
||||
.map((label) => label.name)
|
||||
.filter((name) => Object.prototype.hasOwnProperty.call(managedLabels, name));
|
||||
|
||||
const labelsToAdd = [...desiredLabels].filter((name) => !currentManagedLabels.includes(name));
|
||||
const labelsToRemove = currentManagedLabels.filter((name) => !desiredLabels.has(name));
|
||||
|
||||
if (labelsToAdd.length > 0) {
|
||||
await github.rest.issues.addLabels({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.issue.number,
|
||||
labels: labelsToAdd
|
||||
});
|
||||
}
|
||||
|
||||
for (const name of labelsToRemove) {
|
||||
await github.rest.issues.removeLabel({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.issue.number,
|
||||
name
|
||||
});
|
||||
}
|
||||
|
||||
core.info(`Managed labels: ${[...desiredLabels].sort().join(', ') || 'none'}`);
|
||||
Reference in New Issue
Block a user