| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394 |
- name: Milestone Sync
- on:
- pull_request_target:
- types:
- - opened
- - reopened
- - ready_for_review
- - edited
- - milestoned
- - closed
- branches:
- - develop
- permissions:
- issues: write
- pull-requests: write
- concurrency:
- group: milestone-sync-${{ github.event.pull_request.number }}
- jobs:
- milestone-sync:
- if: github.repository_owner == 'GameServerManagers'
- runs-on: ubuntu-latest
- steps:
- - name: Set PR milestone and update linked issues
- uses: actions/github-script@v9
- with:
- script: |
- const { owner, repo } = context.repo;
- const pr = context.payload.pull_request;
- const action = context.payload.action;
- const fixedLabel = 'status: fixed in develop';
- if (action === 'closed' && !pr.merged) {
- return;
- }
- let milestone = pr.milestone;
- if (!milestone && ['opened', 'reopened', 'ready_for_review'].includes(action)) {
- const open = await github.paginate(github.rest.issues.listMilestones, { owner, repo, state: 'open', per_page: 100 });
- open.sort((a, b) => {
- if (a.due_on && b.due_on) return a.due_on.localeCompare(b.due_on);
- if (a.due_on) return -1;
- if (b.due_on) return 1;
- return a.number - b.number;
- });
- if (open.length === 0) {
- core.warning('No open milestone to assign.');
- } else {
- milestone = open[0];
- await github.rest.issues.update({ owner, repo, issue_number: pr.number, milestone: milestone.number });
- core.info(`Set PR #${pr.number} milestone to ${milestone.title}.`);
- }
- }
- const body = (pr.body || '').replace(/<!--[\s\S]*?-->/g, '');
- const issueRef = /\b(close[sd]?|fix(?:e[sd])?|resolve[sd]?|related to):?\s+(?:([\w.-]+)\/([\w.-]+))?#(\d+)/gi;
- const issues = new Map();
- for (const m of body.matchAll(issueRef)) {
- if (m[2] && (m[2].toLowerCase() !== owner.toLowerCase() || m[3].toLowerCase() !== repo.toLowerCase())) {
- continue;
- }
- const number = Number(m[4]);
- const closing = !/^related to$/i.test(m[1]);
- issues.set(number, issues.get(number) || closing);
- }
- for (const [number, closing] of issues) {
- let issue;
- try {
- ({ data: issue } = await github.rest.issues.get({ owner, repo, issue_number: number }));
- } catch (error) {
- core.warning(`Could not read #${number}: ${error.message}`);
- continue;
- }
- if (issue.pull_request) {
- continue;
- }
- if (milestone && issue.milestone?.number !== milestone.number) {
- if (issue.milestone && !pr.merged) {
- core.info(`#${number} is in ${issue.milestone.title}; it will move to ${milestone.title} when this PR merges.`);
- } else {
- await github.rest.issues.update({ owner, repo, issue_number: number, milestone: milestone.number });
- core.info(`Set #${number} milestone to ${milestone.title}.`);
- }
- }
- if (pr.merged && closing && issue.state === 'open' && !issue.labels.some((l) => (l.name || l) === fixedLabel)) {
- await github.rest.issues.addLabels({ owner, repo, issue_number: number, labels: [fixedLabel] });
- core.info(`Labelled #${number} "${fixedLabel}".`);
- }
- }
|