compliance-close.yml 3.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. name: compliance-close
  2. on:
  3. schedule:
  4. # Run every 30 minutes to check for expired compliance windows
  5. - cron: "*/30 * * * *"
  6. workflow_dispatch:
  7. permissions:
  8. contents: read
  9. issues: write
  10. pull-requests: write
  11. jobs:
  12. close-non-compliant:
  13. runs-on: ubuntu-latest
  14. steps:
  15. - name: Close non-compliant issues and PRs after 2 hours
  16. uses: actions/github-script@v7
  17. with:
  18. script: |
  19. const { data: items } = await github.rest.issues.listForRepo({
  20. owner: context.repo.owner,
  21. repo: context.repo.repo,
  22. labels: 'needs:compliance',
  23. state: 'open',
  24. per_page: 100,
  25. });
  26. if (items.length === 0) {
  27. core.info('No open issues/PRs with needs:compliance label');
  28. return;
  29. }
  30. const now = Date.now();
  31. const twoHours = 2 * 60 * 60 * 1000;
  32. for (const item of items) {
  33. const isPR = !!item.pull_request;
  34. const kind = isPR ? 'PR' : 'issue';
  35. const { data: comments } = await github.rest.issues.listComments({
  36. owner: context.repo.owner,
  37. repo: context.repo.repo,
  38. issue_number: item.number,
  39. });
  40. const complianceComment = comments.find(c => c.body.includes('<!-- issue-compliance -->'));
  41. if (!complianceComment) continue;
  42. const commentAge = now - new Date(complianceComment.created_at).getTime();
  43. if (commentAge < twoHours) {
  44. core.info(`${kind} #${item.number} still within 2-hour window (${Math.round(commentAge / 60000)}m elapsed)`);
  45. continue;
  46. }
  47. const closeMessage = isPR
  48. ? 'This pull request has been automatically closed because it was not updated to meet our [contributing guidelines](../blob/dev/CONTRIBUTING.md) within the 2-hour window.\n\nFeel free to open a new pull request that follows our guidelines.'
  49. : 'This issue has been automatically closed because it was not updated to meet our [contributing guidelines](../blob/dev/CONTRIBUTING.md) within the 2-hour window.\n\nFeel free to open a new issue that follows our issue templates.';
  50. await github.rest.issues.createComment({
  51. owner: context.repo.owner,
  52. repo: context.repo.repo,
  53. issue_number: item.number,
  54. body: closeMessage,
  55. });
  56. try {
  57. await github.rest.issues.removeLabel({
  58. owner: context.repo.owner,
  59. repo: context.repo.repo,
  60. issue_number: item.number,
  61. name: 'needs:compliance',
  62. });
  63. } catch (e) {}
  64. if (isPR) {
  65. await github.rest.pulls.update({
  66. owner: context.repo.owner,
  67. repo: context.repo.repo,
  68. pull_number: item.number,
  69. state: 'closed',
  70. });
  71. } else {
  72. await github.rest.issues.update({
  73. owner: context.repo.owner,
  74. repo: context.repo.repo,
  75. issue_number: item.number,
  76. state: 'closed',
  77. state_reason: 'not_planned',
  78. });
  79. }
  80. core.info(`Closed non-compliant ${kind} #${item.number} after 2-hour window`);
  81. }