[codex] fix metadata sync fallback and docs alignment #102
Workflow file for this run
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: Checklist Finalization | |
| on: | |
| issues: | |
| types: [closed] | |
| pull_request_target: | |
| types: [closed] | |
| permissions: | |
| contents: read | |
| issues: write | |
| pull-requests: write | |
| jobs: | |
| finalize-issue-checklists: | |
| if: github.event_name == 'issues' && github.event.issue.state == 'closed' && github.event.issue.state_reason != 'not_planned' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Finalise issue checklist sections | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const marker = '<!-- checklist-finalisation -->'; | |
| const issue = context.payload.issue; | |
| const body = issue.body || ''; | |
| const updated = finaliseChecklistSections(body, [ | |
| /^##\s+Definition of Ready \(DoR\)\s*$/im, | |
| /^##\s+Definition of Done \(DoD\)\s*$/im, | |
| ]); | |
| if (updated === body) { | |
| core.info(`Issue #${issue.number} already has finalised checklist sections.`); | |
| return; | |
| } | |
| await github.rest.issues.update({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: issue.number, | |
| body: updated, | |
| }); | |
| await addOrUpdateMarkerComment(issue.number, marker, '✅ Issue checklists finalised after closure.'); | |
| core.info(`Finalised checklist sections on issue #${issue.number}.`); | |
| function sectionBounds(bodyText, headingRegex) { | |
| const text = (bodyText || '').replace(/\r\n/g, '\n'); | |
| const match = text.match(headingRegex); | |
| if (!match || match.index === undefined) { | |
| return null; | |
| } | |
| const start = match.index + match[0].length; | |
| const remainder = text.slice(start); | |
| const nextHeading = remainder.match(/^##\s+.+$/m); | |
| const end = nextHeading ? start + nextHeading.index : text.length; | |
| return { start, end, text }; | |
| } | |
| function completeChecklistItems(sectionText) { | |
| return sectionText.replace(/(^|\n)(\s*-\s*)\[\s\](\s*)/g, '$1$2[x]$3'); | |
| } | |
| function finaliseChecklistSections(bodyText, headings) { | |
| let nextBody = (bodyText || '').replace(/\r\n/g, '\n'); | |
| let changed = false; | |
| for (const headingRegex of headings) { | |
| const bounds = sectionBounds(nextBody, headingRegex); | |
| if (!bounds) { | |
| continue; | |
| } | |
| const section = nextBody.slice(bounds.start, bounds.end); | |
| const updatedSection = completeChecklistItems(section); | |
| if (updatedSection !== section) { | |
| nextBody = `${nextBody.slice(0, bounds.start)}${updatedSection}${nextBody.slice(bounds.end)}`; | |
| changed = true; | |
| } | |
| } | |
| return changed ? nextBody : bodyText; | |
| } | |
| async function addOrUpdateMarkerComment(issueNumber, markerText, message) { | |
| const comments = await github.paginate(github.rest.issues.listComments, { | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: issueNumber, | |
| per_page: 100, | |
| }); | |
| const existing = comments.find((comment) => | |
| comment.user?.type === 'Bot' && comment.body?.includes(markerText), | |
| ); | |
| const body = [markerText, message].join('\n'); | |
| if (existing) { | |
| await github.rest.issues.updateComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| comment_id: existing.id, | |
| body, | |
| }); | |
| return; | |
| } | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: issueNumber, | |
| body, | |
| }); | |
| } | |
| finalize-pr-checklists: | |
| if: github.event_name == 'pull_request_target' && github.event.pull_request.merged == true | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Finalise PR checklist sections | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const marker = '<!-- checklist-finalisation -->'; | |
| const pr = context.payload.pull_request; | |
| const body = pr.body || ''; | |
| const updated = finaliseChecklistSections(body, [ | |
| /^###\s+Checklist\s+\(Global DoD\s*\/\s*PR\)\s*$/im, | |
| ]); | |
| if (updated === body) { | |
| core.info(`PR #${pr.number} already has finalised checklist sections.`); | |
| return; | |
| } | |
| await github.rest.issues.update({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: pr.number, | |
| body: updated, | |
| }); | |
| await addOrUpdateMarkerComment(pr.number, marker, '✅ PR checklists finalised after merge.'); | |
| core.info(`Finalised checklist sections on PR #${pr.number}.`); | |
| function sectionBounds(bodyText, headingRegex) { | |
| const text = (bodyText || '').replace(/\r\n/g, '\n'); | |
| const match = text.match(headingRegex); | |
| if (!match || match.index === undefined) { | |
| return null; | |
| } | |
| const start = match.index + match[0].length; | |
| const remainder = text.slice(start); | |
| const nextHeading = remainder.match(/^##\s+.+$/m); | |
| const end = nextHeading ? start + nextHeading.index : text.length; | |
| return { start, end, text }; | |
| } | |
| function completeChecklistItems(sectionText) { | |
| return sectionText.replace(/(^|\n)(\s*-\s*)\[\s\](\s*)/g, '$1$2[x]$3'); | |
| } | |
| function finaliseChecklistSections(bodyText, headings) { | |
| let nextBody = (bodyText || '').replace(/\r\n/g, '\n'); | |
| let changed = false; | |
| for (const headingRegex of headings) { | |
| const bounds = sectionBounds(nextBody, headingRegex); | |
| if (!bounds) { | |
| continue; | |
| } | |
| const section = nextBody.slice(bounds.start, bounds.end); | |
| const updatedSection = completeChecklistItems(section); | |
| if (updatedSection !== section) { | |
| nextBody = `${nextBody.slice(0, bounds.start)}${updatedSection}${nextBody.slice(bounds.end)}`; | |
| changed = true; | |
| } | |
| } | |
| return changed ? nextBody : bodyText; | |
| } | |
| async function addOrUpdateMarkerComment(issueNumber, markerText, message) { | |
| const comments = await github.paginate(github.rest.issues.listComments, { | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: issueNumber, | |
| per_page: 100, | |
| }); | |
| const existing = comments.find((comment) => | |
| comment.user?.type === 'Bot' && comment.body?.includes(markerText), | |
| ); | |
| const body = [markerText, message].join('\n'); | |
| if (existing) { | |
| await github.rest.issues.updateComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| comment_id: existing.id, | |
| body, | |
| }); | |
| return; | |
| } | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: issueNumber, | |
| body, | |
| }); | |
| } |