mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-05-14 00:52:04 +00:00
PR LabelBot: allow users to tag their PRs (#13182)
* Add PR label bot workflow Co-Authored-By: Rodrigo Faselli <162915171+RF47@users.noreply.github.com> * LabelBot add to bot add-label --------- Co-authored-by: Rodrigo Faselli <162915171+RF47@users.noreply.github.com>
This commit is contained in:
267
.github/workflows/pr-label-bot.yml
vendored
Normal file
267
.github/workflows/pr-label-bot.yml
vendored
Normal file
@@ -0,0 +1,267 @@
|
||||
name: PR Label Bot
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
- reopened
|
||||
issue_comment:
|
||||
types:
|
||||
- created
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
issues: write
|
||||
|
||||
jobs:
|
||||
request-label:
|
||||
if: github.event_name == 'pull_request_target'
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
issues: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Ask PR author for label
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
function isPermissionDenied(error) {
|
||||
return error && error.status === 403 && /Resource not accessible by integration/i.test(error.message || '');
|
||||
}
|
||||
|
||||
const allowedLabels = [
|
||||
'bug-fix',
|
||||
'enhancement',
|
||||
'Localization',
|
||||
'profile',
|
||||
'QoL',
|
||||
'UI/UX',
|
||||
'dependencies'
|
||||
];
|
||||
const pr = context.payload.pull_request;
|
||||
const labelsList = `${allowedLabels
|
||||
.slice(0, -1)
|
||||
.map((label) => `\`${label}\``)
|
||||
.join(', ')} and \`${allowedLabels[allowedLabels.length - 1]}\`.`;
|
||||
const examplesText = [
|
||||
'```',
|
||||
'/bot add-label bug-fix',
|
||||
'```',
|
||||
'```',
|
||||
'/bot add-label bug-fix, UI/UX',
|
||||
'```',
|
||||
'```',
|
||||
'/bot remove-label bug-fix, UI/UX',
|
||||
'```'
|
||||
].join('\n');
|
||||
|
||||
try {
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: pr.number,
|
||||
body:
|
||||
`Hi @${pr.user.login}, you can manage the labels for this PR by \`/bot add-label\` and \`/bot remove-label\`\n\n` +
|
||||
`Allowed labels are:\n${labelsList}\n\n` +
|
||||
`Examples:\n${examplesText}`
|
||||
});
|
||||
} catch (error) {
|
||||
if (isPermissionDenied(error)) {
|
||||
core.warning(
|
||||
'Skipping PR comment because token cannot write. Enable Actions write permissions, ' +
|
||||
'or run with a token that has issues:write and pull_requests:write.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
|
||||
apply-label:
|
||||
if: github.event_name == 'issue_comment'
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
issues: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Apply label command from PR author
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
function isPermissionDenied(error) {
|
||||
return error && error.status === 403 && /Resource not accessible by integration/i.test(error.message || '');
|
||||
}
|
||||
|
||||
const allowedLabels = [
|
||||
'bug-fix',
|
||||
'enhancement',
|
||||
'Localization',
|
||||
'profile',
|
||||
'QoL',
|
||||
'UI/UX',
|
||||
'dependencies'
|
||||
];
|
||||
|
||||
const issue = context.payload.issue;
|
||||
if (!issue.pull_request) {
|
||||
core.info('Ignoring comment that is not on a pull request.');
|
||||
return;
|
||||
}
|
||||
|
||||
const body = (context.payload.comment.body || '').trim();
|
||||
const commandLine = body
|
||||
.split('\n')
|
||||
.map((line) => line.trim())
|
||||
.find((line) => /^\/bot\s+(add-label|remove-label)(?:\s*:\s*|\s+)/i.test(line));
|
||||
|
||||
if (!commandLine) {
|
||||
core.info('No /bot add-label or /bot remove-label command found.');
|
||||
return;
|
||||
}
|
||||
|
||||
const commandMatch = commandLine.match(/^\/bot\s+(add-label|remove-label)(?:\s*:\s*|\s+)(.+)\s*$/i);
|
||||
if (!commandMatch) {
|
||||
core.info('Label command format is invalid.');
|
||||
return;
|
||||
}
|
||||
|
||||
const action = commandMatch[1].toLowerCase() === 'add-label' ? 'add' : 'remove';
|
||||
let labelsExpr = (commandMatch[2] || '').trim();
|
||||
if (!labelsExpr) {
|
||||
core.info('Label command is missing label name.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (labelsExpr.startsWith('[') && labelsExpr.endsWith(']')) {
|
||||
labelsExpr = labelsExpr.slice(1, -1).trim();
|
||||
}
|
||||
|
||||
const requestedRawLabels = labelsExpr
|
||||
.split(',')
|
||||
.map((part) => part.trim())
|
||||
.filter(Boolean);
|
||||
|
||||
if (!requestedRawLabels.length) {
|
||||
core.info('No labels were provided in the command.');
|
||||
return;
|
||||
}
|
||||
|
||||
const { data: pr } = await github.rest.pulls.get({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: issue.number
|
||||
});
|
||||
|
||||
const commenter = context.payload.comment.user.login;
|
||||
if (commenter !== pr.user.login) {
|
||||
core.info('Ignoring command because commenter is not the PR author.');
|
||||
return;
|
||||
}
|
||||
|
||||
const labelsByLower = new Map(
|
||||
allowedLabels.map((label) => [label.toLowerCase(), label])
|
||||
);
|
||||
|
||||
const resolvedLabels = [];
|
||||
const invalidLabels = [];
|
||||
|
||||
for (const rawLabel of requestedRawLabels) {
|
||||
const resolved = labelsByLower.get(rawLabel.toLowerCase());
|
||||
if (resolved) {
|
||||
resolvedLabels.push(resolved);
|
||||
} else {
|
||||
invalidLabels.push(rawLabel);
|
||||
}
|
||||
}
|
||||
|
||||
if (invalidLabels.length) {
|
||||
const allowedText = allowedLabels.map((label) => `\`${label}\``).join(', ');
|
||||
const invalidText = invalidLabels.map((label) => `\`${label}\``).join(', ');
|
||||
try {
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issue.number,
|
||||
body:
|
||||
`@${commenter} invalid label(s): ${invalidText}.\n\n` +
|
||||
`Allowed labels: ${allowedText}\n\n` +
|
||||
`Use:\n` +
|
||||
`- \`/bot add-label label\`\n` +
|
||||
`- \`/bot remove-label label\`\n` +
|
||||
`- \`/bot add-label label1, label2\``
|
||||
});
|
||||
} catch (error) {
|
||||
if (isPermissionDenied(error)) {
|
||||
core.warning('Cannot post invalid-label feedback because token cannot write comments.');
|
||||
return;
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const uniqueRequestedLabels = [...new Set(resolvedLabels)];
|
||||
|
||||
if (action === 'add') {
|
||||
try {
|
||||
await github.rest.issues.addLabels({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issue.number,
|
||||
labels: uniqueRequestedLabels
|
||||
});
|
||||
} catch (error) {
|
||||
if (isPermissionDenied(error)) {
|
||||
core.warning(
|
||||
'Cannot add labels because token cannot write. Enable Actions write permissions, ' +
|
||||
'or run with a token that has issues:write and pull_requests:write.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
|
||||
core.info(`Added labels: ${uniqueRequestedLabels.join(', ')}`);
|
||||
return;
|
||||
}
|
||||
|
||||
let removedCount = 0;
|
||||
try {
|
||||
for (const label of uniqueRequestedLabels) {
|
||||
try {
|
||||
await github.rest.issues.removeLabel({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issue.number,
|
||||
name: label
|
||||
});
|
||||
removedCount += 1;
|
||||
} catch (error) {
|
||||
if (isPermissionDenied(error)) {
|
||||
core.warning(
|
||||
'Cannot remove labels because token cannot write. Enable Actions write permissions, ' +
|
||||
'or run with a token that has issues:write and pull_requests:write.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (error.status === 404) {
|
||||
core.info(`Label is not currently applied: ${label}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
core.info(`Removed labels count: ${removedCount}`);
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
core.info(`Processed label command: ${action} ${uniqueRequestedLabels.join(', ')}`);
|
||||
Reference in New Issue
Block a user