From 73653862ff9e2a374be7fe9b12b01e4d05202307 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Rausell=20Guiard?= <33221237+AlvaroRausell@users.noreply.github.com> Date: Mon, 27 Oct 2025 16:01:58 +0000 Subject: [PATCH 1/3] Automatically label PRs based on changes made --- .github/pr-labeler.yml | 16 +++ .github/pull_request_template.md | 19 ++++ .github/workflows/pr-template-validation.yml | 103 +++++++++++++++++++ 3 files changed, 138 insertions(+) create mode 100644 .github/pr-labeler.yml create mode 100644 .github/pull_request_template.md create mode 100644 .github/workflows/pr-template-validation.yml diff --git a/.github/pr-labeler.yml b/.github/pr-labeler.yml new file mode 100644 index 0000000000..e9859fe9f8 --- /dev/null +++ b/.github/pr-labeler.yml @@ -0,0 +1,16 @@ +target:images: + - 'target:images' +target:docs-only: + - 'target:docs-only' +target:other: + - 'target:other' +change:bugfix: + - 'change:bugfix' +change:feature: + - 'change:feature' +change:breaking: + - 'change:breaking' +change:other: + - 'change:other' +change:na: + - 'change:na' diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000000..fd577a0283 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,19 @@ +Ref: **Insert issue URL** + +# What approach did you choose and why? + +# What are you changing? + + +- *images* +- *docs only* +- *Other* + +# If changing images, what kind of change is it? + + +- *Bug/security fix* +- *New feature* +- *Breaking change (i.e. Change to default OS, incompatible tooling change etc)* +- *Other* +- *NA* diff --git a/.github/workflows/pr-template-validation.yml b/.github/workflows/pr-template-validation.yml new file mode 100644 index 0000000000..97703132e5 --- /dev/null +++ b/.github/workflows/pr-template-validation.yml @@ -0,0 +1,103 @@ +name: PR Template Validation + +on: + pull_request_target: + types: + - opened + - edited + +permissions: + contents: read + pull-requests: write + issues: write + +jobs: + validate-and-label: + if: github.event.action == 'opened' || (github.event.action == 'edited' && github.event.changes.body != null) + runs-on: ubuntu-latest + steps: + - name: Validate PR template selections + uses: actions/github-script@v7 + with: + script: | + const {owner, repo} = context.repo; + const issue_number = context.payload.pull_request.number; + const body = (context.payload.pull_request.body || '').trim(); + const optionPattern = /- \[[ xX]\] .*?/g; + const groups = { + 'What are you changing?': ['target:images', 'target:docs-only', 'target:other'], + 'If changing images, what kind of change is it?': ['change:bugfix', 'change:feature', 'change:breaking', 'change:other', 'change:na'] + }; + const marker = ''; + + const selections = new Map(); + let match; + while ((match = optionPattern.exec(body)) !== null) { + const line = match[0]; + const tag = match[1]; + const isChecked = /\[[xX]\]/.test(line); + selections.set(tag, isChecked); + } + + const errors = []; + for (const [section, tags] of Object.entries(groups)) { + const checkedCount = tags.reduce((count, tag) => count + (selections.get(tag) ? 1 : 0), 0); + if (checkedCount !== 1) { + errors.push(`${section} must have exactly one option selected (found ${checkedCount}).`); + } + } + + const {data: comments} = await github.rest.issues.listComments({ + owner, + repo, + issue_number, + per_page: 100 + }); + const existing = comments.find(comment => comment.body && comment.body.includes(marker)); + + if (errors.length) { + const message = [ + marker, + '⚠️ **PR Template Validation Failed**', + '', + 'Please update the PR description so each section has exactly one option selected:', + ...errors.map(error => `- ${error}`), + '', + 'Once you update the description, this workflow will re-run automatically.' + ].join('\n'); + + if (existing) { + await github.rest.issues.updateComment({ + owner, + repo, + comment_id: existing.id, + body: message + }); + } else { + await github.rest.issues.createComment({ + owner, + repo, + issue_number, + body: message + }); + } + + core.setFailed(errors.join(' ')); + } else { + if (existing) { + await github.rest.issues.deleteComment({ + owner, + repo, + comment_id: existing.id + }); + } + core.info('PR template selections validated.'); + } + - name: Apply labels from PR template markers + uses: github/issue-labeler@v3.3 + with: + repo-token: ${{ github.token }} + configuration-path: .github/pr-labeler.yml + include-title: 0 + include-body: 1 + sync-labels: 1 From 0a57c108e9bc4a4e30ebfc69225937c70a25e974 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Rausell=20Guiard?= <33221237+AlvaroRausell@users.noreply.github.com> Date: Mon, 27 Oct 2025 16:23:10 +0000 Subject: [PATCH 2/3] Check boxes --- .github/pull_request_template.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index fd577a0283..517d97e86d 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -5,15 +5,15 @@ Ref: **Insert issue URL** # What are you changing? -- *images* -- *docs only* -- *Other* +- [ ] *images* +- [ ] *docs only* +- [ ] *Other* # If changing images, what kind of change is it? -- *Bug/security fix* -- *New feature* -- *Breaking change (i.e. Change to default OS, incompatible tooling change etc)* -- *Other* -- *NA* +- [ ] *Bug/security fix* +- [ ] *New feature* +- [ ] *Breaking change (i.e. Change to default OS, incompatible tooling change etc)* +- [ ] *Other* +- [ ] *NA* From 0591dcef7fd60233368258c9fb88d5abfe6aa2a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Rausell=20Guiard?= <33221237+AlvaroRausell@users.noreply.github.com> Date: Mon, 27 Oct 2025 16:30:04 +0000 Subject: [PATCH 3/3] N/A --- .github/pull_request_template.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 517d97e86d..844aca2798 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -16,4 +16,4 @@ Ref: **Insert issue URL** - [ ] *New feature* - [ ] *Breaking change (i.e. Change to default OS, incompatible tooling change etc)* - [ ] *Other* -- [ ] *NA* +- [ ] *N/A*