From 48144e2c0960e5a2f7d11699faa830e10849eed7 Mon Sep 17 00:00:00 2001 From: Nabin Mulepati Date: Mon, 17 Aug 2026 16:39:42 -0600 Subject: [PATCH 1/6] docs: add issue-first contribution guidelines --- .github/pull_request_template.md | 5 +++++ CONTRIBUTING.md | 24 ++++++++++++++++++++++++ README.md | 4 ++++ 3 files changed, 33 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index aa4852d..15c09d8 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -2,8 +2,13 @@ +## Linked Issue + + + ## Checklist +- [ ] Linked to the approved issue this PR addresses (`Fixes #NNN` or `Closes #NNN`), or I am a repository collaborator performing routine maintenance - [ ] Follows the template structure (`config.py`, `impl.py`, `plugin.py`) if adding a plugin - [ ] `assert_valid_plugin(plugin)` passes - [ ] Unit tests included and passing (`make test-plugin PLUGIN=`) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..053e79d --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,24 @@ +# Contributing to NeMo Data Designer Plugins + +Thank you for your interest in contributing to the NeMo Data Designer plugin catalog. + +## Before You Open a Pull Request + +External contributors must open a GitHub issue before opening a pull request. This gives maintainers an opportunity to confirm that the proposed change is in scope and to align on the approach before implementation begins. + +1. Search the [existing issues](https://github.com/NVIDIA-NeMo/DataDesignerPlugins/issues) for related work. +2. If no relevant issue exists, [open an issue](https://github.com/NVIDIA-NeMo/DataDesignerPlugins/issues/new) describing the problem, proposed change, and affected plugin or repository component. +3. Wait for a maintainer to confirm that the contribution is ready to proceed. +4. Link the pull request to the issue with `Fixes #NNN` or `Closes #NNN`. + +This issue-first requirement applies to external contributors. Repository collaborators may open pull requests directly for routine maintenance and already-planned work. + +## Preparing Your Change + +- Follow the repository structure and development guidance in the [README](README.md) and [AGENTS.md](AGENTS.md). +- Add or update tests for changed behavior. +- Run the relevant checks described in the README. +- Keep the pull request focused on the agreed issue scope. +- Complete the pull request template and describe how the change was validated. + +Plugin changes should follow the reference implementation under `plugins/data-designer-template/` and remain self-contained within their plugin package. diff --git a/README.md b/README.md index 219d460..d5dc22e 100644 --- a/README.md +++ b/README.md @@ -128,6 +128,10 @@ Before a package's first release, register it once with See [docs/releasing.md](docs/releasing.md) for the full release guide. +## Contributing + +Community contributions are welcome. External contributors must open an issue and receive maintainer confirmation before opening a pull request. See [CONTRIBUTING.md](CONTRIBUTING.md) for the contribution workflow. + ## License Apache-2.0. See [LICENSE](LICENSE). From 5efcdca4ef76c1e5bfde1f2a5d1e802ce44a5b5b Mon Sep 17 00:00:00 2001 From: Nabin Mulepati Date: Mon, 17 Aug 2026 16:50:41 -0600 Subject: [PATCH 2/6] docs: require triaged issues for community PRs --- .github/pull_request_template.md | 4 ++-- CONTRIBUTING.md | 8 ++++---- README.md | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 15c09d8..e66f613 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -4,11 +4,11 @@ ## Linked Issue - + ## Checklist -- [ ] Linked to the approved issue this PR addresses (`Fixes #NNN` or `Closes #NNN`), or I am a repository collaborator performing routine maintenance +- [ ] Linked to the triaged issue this PR addresses (`Fixes #NNN` or `Closes #NNN`), or I am a repository collaborator performing routine maintenance - [ ] Follows the template structure (`config.py`, `impl.py`, `plugin.py`) if adding a plugin - [ ] `assert_valid_plugin(plugin)` passes - [ ] Unit tests included and passing (`make test-plugin PLUGIN=`) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 053e79d..a2b4d56 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,14 +4,14 @@ Thank you for your interest in contributing to the NeMo Data Designer plugin cat ## Before You Open a Pull Request -External contributors must open a GitHub issue before opening a pull request. This gives maintainers an opportunity to confirm that the proposed change is in scope and to align on the approach before implementation begins. +External contributors must open a GitHub issue before opening a pull request. Maintainers apply the [`triaged`](https://github.com/NVIDIA-NeMo/DataDesignerPlugins/labels/triaged) label when an issue has been reviewed, approved, and is ready to be worked on. 1. Search the [existing issues](https://github.com/NVIDIA-NeMo/DataDesignerPlugins/issues) for related work. 2. If no relevant issue exists, [open an issue](https://github.com/NVIDIA-NeMo/DataDesignerPlugins/issues/new) describing the problem, proposed change, and affected plugin or repository component. -3. Wait for a maintainer to confirm that the contribution is ready to proceed. -4. Link the pull request to the issue with `Fixes #NNN` or `Closes #NNN`. +3. Wait for a maintainer to apply the `triaged` label before beginning implementation. +4. Link the pull request to the triaged issue with `Fixes #NNN` or `Closes #NNN`. -This issue-first requirement applies to external contributors. Repository collaborators may open pull requests directly for routine maintenance and already-planned work. +Pull requests from external contributors must link to a triaged issue. Repository collaborators may open pull requests directly for routine maintenance and already-planned work. ## Preparing Your Change diff --git a/README.md b/README.md index d5dc22e..2c87701 100644 --- a/README.md +++ b/README.md @@ -130,7 +130,7 @@ See [docs/releasing.md](docs/releasing.md) for the full release guide. ## Contributing -Community contributions are welcome. External contributors must open an issue and receive maintainer confirmation before opening a pull request. See [CONTRIBUTING.md](CONTRIBUTING.md) for the contribution workflow. +Community contributions are welcome. External contributors must open an issue and wait for the `triaged` label before beginning implementation or opening a pull request. See [CONTRIBUTING.md](CONTRIBUTING.md) for the contribution workflow. ## License From 49e2bf5cc766ea56d19de4337550ae0d0a4936c7 Mon Sep 17 00:00:00 2001 From: Nabin Mulepati Date: Tue, 18 Aug 2026 09:26:48 -0600 Subject: [PATCH 3/6] ci: enforce linked triaged issues --- .github/pull_request_template.md | 2 +- .github/workflows/pr-linked-issue.yml | 242 ++++++++++++++++++++++++++ 2 files changed, 243 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/pr-linked-issue.yml diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index e66f613..060d5c6 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -8,7 +8,7 @@ ## Checklist -- [ ] Linked to the triaged issue this PR addresses (`Fixes #NNN` or `Closes #NNN`), or I am a repository collaborator performing routine maintenance +- [ ] Linked to the triaged issue this PR addresses (`Fixes #NNN` or `Closes #NNN`), or I am a repository collaborator performing routine maintenance or already-planned work - [ ] Follows the template structure (`config.py`, `impl.py`, `plugin.py`) if adding a plugin - [ ] `assert_valid_plugin(plugin)` passes - [ ] Unit tests included and passing (`make test-plugin PLUGIN=`) diff --git a/.github/workflows/pr-linked-issue.yml b/.github/workflows/pr-linked-issue.yml new file mode 100644 index 0000000..e4150df --- /dev/null +++ b/.github/workflows/pr-linked-issue.yml @@ -0,0 +1,242 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +name: "Linked Issue Check" + +on: + # Re-check when a PR is opened or its body or commits change. + pull_request_target: + types: [opened, edited, synchronize, reopened] + branches: [main] + + # Re-check open PRs when a maintainer adds the "triaged" label to an issue. + issues: + types: [labeled] + +permissions: + contents: read + pull-requests: write + issues: read + +jobs: + # SECURITY: This workflow uses pull_request_target to post comments on fork + # PRs. It MUST NOT check out or execute code from the PR branch. All inputs + # from the PR are read through GitHub-controlled metadata and APIs only. + check: + if: >- + github.repository_owner == 'NVIDIA-NeMo' + && github.event_name != 'issues' + runs-on: ubuntu-latest + steps: + - name: Check author permissions + id: author + env: + GH_TOKEN: ${{ github.token }} + PR_AUTHOR: ${{ github.event.pull_request.user.login }} + run: | + USER="$PR_AUTHOR" + + # Bots that are always allowed. + if [ "$USER" = "dependabot[bot]" ]; then + echo "is_collaborator=true" >> "$GITHUB_OUTPUT" + exit 0 + fi + + PERMISSION=$(gh api "repos/${{ github.repository }}/collaborators/${USER}/permission" \ + --jq '.permission' 2>/dev/null || echo "none") + echo "permission=${PERMISSION}" + + if [ "$PERMISSION" = "admin" ] || [ "$PERMISSION" = "write" ]; then + echo "is_collaborator=true" >> "$GITHUB_OUTPUT" + else + echo "is_collaborator=false" >> "$GITHUB_OUTPUT" + fi + + - name: Parse issue reference from PR body + id: parse + if: steps.author.outputs.is_collaborator != 'true' + env: + PR_BODY: ${{ github.event.pull_request.body }} + run: | + if [ -z "$PR_BODY" ] || [ "$PR_BODY" = "null" ]; then + echo "issue_num=" >> "$GITHUB_OUTPUT" + echo "No PR body found" + exit 0 + fi + + # Case-insensitive match for Fixes #N, Closes #N, or Resolves #N. + printf '%s' "$PR_BODY" > /tmp/pr-body-raw.txt + ISSUE_NUM=$(grep -ioP '(?:fixes|closes|resolves)\s+#\K\d+' /tmp/pr-body-raw.txt | head -1 || true) + echo "issue_num=${ISSUE_NUM}" >> "$GITHUB_OUTPUT" + echo "Parsed issue number: ${ISSUE_NUM:-}" + + - name: Validate issue exists and is triaged + id: validate + if: steps.author.outputs.is_collaborator != 'true' && steps.parse.outputs.issue_num != '' + env: + GH_TOKEN: ${{ github.token }} + ISSUE_NUM: ${{ steps.parse.outputs.issue_num }} + run: | + RESPONSE=$(gh api "repos/${{ github.repository }}/issues/${ISSUE_NUM}" 2>/dev/null) || { + echo "issue_exists=false" >> "$GITHUB_OUTPUT" + echo "is_triaged=false" >> "$GITHUB_OUTPUT" + echo "Issue #${ISSUE_NUM} not found" + exit 0 + } + + # GitHub's issues API returns both issues and pull requests. + IS_PR=$(echo "$RESPONSE" | jq -r 'has("pull_request")') + if [ "$IS_PR" = "true" ]; then + echo "issue_exists=false" >> "$GITHUB_OUTPUT" + echo "is_triaged=false" >> "$GITHUB_OUTPUT" + echo "#${ISSUE_NUM} is a pull request, not an issue" + exit 0 + fi + + echo "issue_exists=true" >> "$GITHUB_OUTPUT" + + TRIAGED=$(echo "$RESPONSE" | jq -r '[.labels[].name] | any(. == "triaged")') + echo "is_triaged=${TRIAGED}" >> "$GITHUB_OUTPUT" + echo "Issue #${ISSUE_NUM} exists, triaged=${TRIAGED}" + + - name: Build comment body and post result + id: comment + env: + GH_TOKEN: ${{ github.token }} + IS_COLLABORATOR: ${{ steps.author.outputs.is_collaborator }} + ISSUE_NUM: ${{ steps.parse.outputs.issue_num }} + ISSUE_EXISTS: ${{ steps.validate.outputs.issue_exists }} + IS_TRIAGED: ${{ steps.validate.outputs.is_triaged }} + PR_NUMBER: ${{ github.event.pull_request.number }} + REPO: ${{ github.repository }} + run: | + MARKER="" + + COMMENT_ID=$(gh api "repos/${REPO}/issues/${PR_NUMBER}/comments" \ + --jq "[.[] | select(.user.login == \"github-actions[bot]\") | select(.body | contains(\"${MARKER}\"))] | last | .id // empty" \ + 2>/dev/null || echo "") + + if [ "$IS_COLLABORATOR" = "true" ]; then + echo "status=pass" >> "$GITHUB_OUTPUT" + if [ -n "$COMMENT_ID" ]; then + gh api -X DELETE "repos/${REPO}/issues/comments/${COMMENT_ID}" || true + fi + exit 0 + fi + + if [ -z "$ISSUE_NUM" ]; then + STATUS="fail" + cat > /tmp/comment-body.md <<'MSG' + + ### Linked Issue Check + + This PR does not reference an issue. External contributions must link to + a triaged issue before the PR can be merged. + + Add one of the following to your PR description: + - `Fixes #` + - `Closes #` + - `Resolves #` + + If no issue exists yet, [open one](https://github.com/NVIDIA-NeMo/DataDesignerPlugins/issues/new) + and a maintainer will triage it. + + See [CONTRIBUTING.md](https://github.com/NVIDIA-NeMo/DataDesignerPlugins/blob/main/CONTRIBUTING.md) + for details. + MSG + elif [ "$ISSUE_EXISTS" != "true" ]; then + STATUS="fail" + cat > /tmp/comment-body.md < + ### Linked Issue Check + + The referenced issue #${ISSUE_NUM} was not found. Please check the issue + number in your PR description. + MSG + elif [ "$IS_TRIAGED" != "true" ]; then + STATUS="fail" + cat > /tmp/comment-body.md < + ### Linked Issue Check + + Issue #${ISSUE_NUM} has not been triaged yet. A maintainer needs to review + the issue and add the `triaged` label before this PR can be merged. + + The check will re-run automatically once the issue is triaged. + MSG + else + STATUS="pass" + fi + + echo "status=${STATUS}" >> "$GITHUB_OUTPUT" + + if [ "$STATUS" = "fail" ]; then + if [ -n "$COMMENT_ID" ]; then + gh api -X PATCH "repos/${REPO}/issues/comments/${COMMENT_ID}" \ + -f body="$(cat /tmp/comment-body.md)" + else + gh api "repos/${REPO}/issues/${PR_NUMBER}/comments" \ + -f body="$(cat /tmp/comment-body.md)" + fi + elif [ -n "$COMMENT_ID" ]; then + gh api -X DELETE "repos/${REPO}/issues/comments/${COMMENT_ID}" || true + fi + + - name: Set check result + if: steps.comment.outputs.status == 'fail' + run: | + echo "::error::Linked issue check failed. See the PR comment for details." + exit 1 + + retrigger: + if: >- + github.repository_owner == 'NVIDIA-NeMo' + && github.event_name == 'issues' + && github.event.label.name == 'triaged' + runs-on: ubuntu-latest + steps: + - name: Find PRs referencing this issue + id: find-prs + env: + GH_TOKEN: ${{ github.token }} + ISSUE_NUMBER: ${{ github.event.issue.number }} + run: | + PRS=$(gh pr list --repo "${{ github.repository }}" --state open \ + --json number,body --limit 200 \ + | jq -r "[.[] | select(.body != null) | select(.body | test(\"(?i)(fixes|closes|resolves)\\\\s+#${ISSUE_NUMBER}\\\\b\")) | .number] | .[]") + + if [ -z "$PRS" ]; then + echo "No open PRs reference issue #${ISSUE_NUMBER}" + echo "prs=" >> "$GITHUB_OUTPUT" + else + echo "Found PRs: ${PRS}" + echo "prs=$(echo "$PRS" | tr '\n' ' ')" >> "$GITHUB_OUTPUT" + fi + + - name: Re-trigger linked issue check + if: steps.find-prs.outputs.prs != '' + env: + GH_TOKEN: ${{ github.token }} + ISSUE_NUMBER: ${{ github.event.issue.number }} + PR_NUMBERS: ${{ steps.find-prs.outputs.prs }} + run: | + TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ) + + for PR_NUM in $PR_NUMBERS; do + echo "Re-triggering check for PR #${PR_NUM}..." + + gh pr view "$PR_NUM" --repo "${{ github.repository }}" --json body -q '.body' > /tmp/current-body.txt + + MARKER="||" \ + /tmp/current-body.txt > /tmp/pr-body.md + else + cp /tmp/current-body.txt /tmp/pr-body.md + printf '\n' "$TIMESTAMP" >> /tmp/pr-body.md + fi + + gh pr edit "$PR_NUM" --repo "${{ github.repository }}" --body-file /tmp/pr-body.md + gh pr comment "$PR_NUM" --repo "${{ github.repository }}" --body \ + "Issue #${ISSUE_NUMBER} has been triaged. The linked issue check is being re-evaluated." + done From 94a7ae99f99f64558e03a6915c9be22ef077e161 Mon Sep 17 00:00:00 2001 From: Nabin Mulepati Date: Wed, 19 Aug 2026 09:20:55 -0600 Subject: [PATCH 4/6] fix: address linked issue workflow review --- .github/pull_request_template.md | 4 +-- .github/workflows/pr-linked-issue.yml | 45 ++++++++++++++++++++++----- CONTRIBUTING.md | 6 ++-- README.md | 2 +- 4 files changed, 43 insertions(+), 14 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 060d5c6..5dc755f 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -4,11 +4,11 @@ ## Linked Issue - + ## Checklist -- [ ] Linked to the triaged issue this PR addresses (`Fixes #NNN` or `Closes #NNN`), or I am a repository collaborator performing routine maintenance or already-planned work +- [ ] Linked to the open, triaged issue this PR addresses (`Fixes #NNN` or `Closes #NNN`), or I am a repository collaborator performing routine maintenance or already-planned work - [ ] Follows the template structure (`config.py`, `impl.py`, `plugin.py`) if adding a plugin - [ ] `assert_valid_plugin(plugin)` passes - [ ] Unit tests included and passing (`make test-plugin PLUGIN=`) diff --git a/.github/workflows/pr-linked-issue.yml b/.github/workflows/pr-linked-issue.yml index e4150df..83b1139 100644 --- a/.github/workflows/pr-linked-issue.yml +++ b/.github/workflows/pr-linked-issue.yml @@ -9,7 +9,7 @@ on: types: [opened, edited, synchronize, reopened] branches: [main] - # Re-check open PRs when a maintainer adds the "triaged" label to an issue. + # Re-check open PRs when a maintainer adds the "triaged" label to an open issue. issues: types: [labeled] @@ -70,7 +70,7 @@ jobs: echo "issue_num=${ISSUE_NUM}" >> "$GITHUB_OUTPUT" echo "Parsed issue number: ${ISSUE_NUM:-}" - - name: Validate issue exists and is triaged + - name: Validate issue is open and triaged id: validate if: steps.author.outputs.is_collaborator != 'true' && steps.parse.outputs.issue_num != '' env: @@ -79,6 +79,7 @@ jobs: run: | RESPONSE=$(gh api "repos/${{ github.repository }}/issues/${ISSUE_NUM}" 2>/dev/null) || { echo "issue_exists=false" >> "$GITHUB_OUTPUT" + echo "is_open=false" >> "$GITHUB_OUTPUT" echo "is_triaged=false" >> "$GITHUB_OUTPUT" echo "Issue #${ISSUE_NUM} not found" exit 0 @@ -88,6 +89,7 @@ jobs: IS_PR=$(echo "$RESPONSE" | jq -r 'has("pull_request")') if [ "$IS_PR" = "true" ]; then echo "issue_exists=false" >> "$GITHUB_OUTPUT" + echo "is_open=false" >> "$GITHUB_OUTPUT" echo "is_triaged=false" >> "$GITHUB_OUTPUT" echo "#${ISSUE_NUM} is a pull request, not an issue" exit 0 @@ -95,9 +97,17 @@ jobs: echo "issue_exists=true" >> "$GITHUB_OUTPUT" + ISSUE_OPEN=$(echo "$RESPONSE" | jq -r '.state == "open"') + echo "is_open=${ISSUE_OPEN}" >> "$GITHUB_OUTPUT" + if [ "$ISSUE_OPEN" != "true" ]; then + echo "is_triaged=false" >> "$GITHUB_OUTPUT" + echo "Issue #${ISSUE_NUM} is closed" + exit 0 + fi + TRIAGED=$(echo "$RESPONSE" | jq -r '[.labels[].name] | any(. == "triaged")') echo "is_triaged=${TRIAGED}" >> "$GITHUB_OUTPUT" - echo "Issue #${ISSUE_NUM} exists, triaged=${TRIAGED}" + echo "Issue #${ISSUE_NUM} is open, triaged=${TRIAGED}" - name: Build comment body and post result id: comment @@ -106,15 +116,18 @@ jobs: IS_COLLABORATOR: ${{ steps.author.outputs.is_collaborator }} ISSUE_NUM: ${{ steps.parse.outputs.issue_num }} ISSUE_EXISTS: ${{ steps.validate.outputs.issue_exists }} + ISSUE_OPEN: ${{ steps.validate.outputs.is_open }} IS_TRIAGED: ${{ steps.validate.outputs.is_triaged }} PR_NUMBER: ${{ github.event.pull_request.number }} REPO: ${{ github.repository }} run: | MARKER="" - COMMENT_ID=$(gh api "repos/${REPO}/issues/${PR_NUMBER}/comments" \ - --jq "[.[] | select(.user.login == \"github-actions[bot]\") | select(.body | contains(\"${MARKER}\"))] | last | .id // empty" \ + COMMENT_IDS=$(gh api --paginate \ + "repos/${REPO}/issues/${PR_NUMBER}/comments?per_page=100" \ + --jq ".[] | select(.user.login == \"github-actions[bot]\") | select(.body | contains(\"${MARKER}\")) | .id" \ 2>/dev/null || echo "") + COMMENT_ID=$(printf '%s\n' "$COMMENT_IDS" | tail -1) if [ "$IS_COLLABORATOR" = "true" ]; then echo "status=pass" >> "$GITHUB_OUTPUT" @@ -131,7 +144,7 @@ jobs: ### Linked Issue Check This PR does not reference an issue. External contributions must link to - a triaged issue before the PR can be merged. + an open, triaged issue for this check to pass. Add one of the following to your PR description: - `Fixes #` @@ -153,6 +166,15 @@ jobs: The referenced issue #${ISSUE_NUM} was not found. Please check the issue number in your PR description. MSG + elif [ "$ISSUE_OPEN" != "true" ]; then + STATUS="fail" + cat > /tmp/comment-body.md < + ### Linked Issue Check + + Issue #${ISSUE_NUM} is closed. Please link an open, triaged issue in your + PR description. + MSG elif [ "$IS_TRIAGED" != "true" ]; then STATUS="fail" cat > /tmp/comment-body.md <[0-9]+)")?) as $reference + | select($reference.issue == $issue) + | .number + ') if [ -z "$PRS" ]; then echo "No open PRs reference issue #${ISSUE_NUMBER}" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a2b4d56..32f86f7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,14 +4,14 @@ Thank you for your interest in contributing to the NeMo Data Designer plugin cat ## Before You Open a Pull Request -External contributors must open a GitHub issue before opening a pull request. Maintainers apply the [`triaged`](https://github.com/NVIDIA-NeMo/DataDesignerPlugins/labels/triaged) label when an issue has been reviewed, approved, and is ready to be worked on. +External contributors are expected to open a GitHub issue before opening a pull request. Maintainers apply the [`triaged`](https://github.com/NVIDIA-NeMo/DataDesignerPlugins/labels/triaged) label when an open issue has been reviewed, approved, and is ready to be worked on. 1. Search the [existing issues](https://github.com/NVIDIA-NeMo/DataDesignerPlugins/issues) for related work. 2. If no relevant issue exists, [open an issue](https://github.com/NVIDIA-NeMo/DataDesignerPlugins/issues/new) describing the problem, proposed change, and affected plugin or repository component. 3. Wait for a maintainer to apply the `triaged` label before beginning implementation. -4. Link the pull request to the triaged issue with `Fixes #NNN` or `Closes #NNN`. +4. Link the pull request to the open, triaged issue with `Fixes #NNN` or `Closes #NNN`. -Pull requests from external contributors must link to a triaged issue. Repository collaborators may open pull requests directly for routine maintenance and already-planned work. +Pull requests from external contributors should link to an open, triaged issue. The linked-issue workflow reports when this policy is not met; repository rules must separately require `Linked Issue Check / check` for that result to block merging. Repository collaborators may open pull requests directly for routine maintenance and already-planned work. ## Preparing Your Change diff --git a/README.md b/README.md index 2c87701..aba7196 100644 --- a/README.md +++ b/README.md @@ -130,7 +130,7 @@ See [docs/releasing.md](docs/releasing.md) for the full release guide. ## Contributing -Community contributions are welcome. External contributors must open an issue and wait for the `triaged` label before beginning implementation or opening a pull request. See [CONTRIBUTING.md](CONTRIBUTING.md) for the contribution workflow. +Community contributions are welcome. External contributors are expected to open an issue and wait for the `triaged` label before beginning implementation or opening a pull request. See [CONTRIBUTING.md](CONTRIBUTING.md) for the contribution workflow and enforcement details. ## License From 74d21fc8ada59036ff96a2b221eaa42bc7cf458e Mon Sep 17 00:00:00 2001 From: Nabin Mulepati Date: Wed, 19 Aug 2026 10:58:58 -0600 Subject: [PATCH 5/6] fix: recheck linked issue state changes Signed-off-by: Nabin Mulepati --- .github/workflows/pr-linked-issue.yml | 37 +++++++++++++++++++++++---- CONTRIBUTING.md | 2 +- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/.github/workflows/pr-linked-issue.yml b/.github/workflows/pr-linked-issue.yml index 83b1139..c2b95c8 100644 --- a/.github/workflows/pr-linked-issue.yml +++ b/.github/workflows/pr-linked-issue.yml @@ -9,9 +9,9 @@ on: types: [opened, edited, synchronize, reopened] branches: [main] - # Re-check open PRs when a maintainer adds the "triaged" label to an open issue. + # Re-check open PRs when linked-issue validity changes. issues: - types: [labeled] + types: [labeled, unlabeled, closed, reopened] permissions: contents: read @@ -214,8 +214,15 @@ jobs: if: >- github.repository_owner == 'NVIDIA-NeMo' && github.event_name == 'issues' - && github.event.label.name == 'triaged' - && github.event.issue.state == 'open' + && ( + github.event.action == 'closed' + || github.event.action == 'reopened' + || ( + (github.event.action == 'labeled' || github.event.action == 'unlabeled') + && github.event.label.name == 'triaged' + && github.event.issue.state == 'open' + ) + ) runs-on: ubuntu-latest steps: - name: Find PRs referencing this issue @@ -246,11 +253,31 @@ jobs: if: steps.find-prs.outputs.prs != '' env: GH_TOKEN: ${{ github.token }} + ISSUE_ACTION: ${{ github.event.action }} ISSUE_NUMBER: ${{ github.event.issue.number }} PR_NUMBERS: ${{ steps.find-prs.outputs.prs }} run: | TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ) + case "$ISSUE_ACTION" in + labeled) + EVENT_DESCRIPTION='received the `triaged` label' + ;; + unlabeled) + EVENT_DESCRIPTION='lost the `triaged` label' + ;; + closed) + EVENT_DESCRIPTION="was closed" + ;; + reopened) + EVENT_DESCRIPTION="was reopened" + ;; + *) + echo "::error::Unsupported issue action: ${ISSUE_ACTION}" + exit 1 + ;; + esac + for PR_NUM in $PR_NUMBERS; do echo "Re-triggering check for PR #${PR_NUM}..." @@ -267,5 +294,5 @@ jobs: gh pr edit "$PR_NUM" --repo "${{ github.repository }}" --body-file /tmp/pr-body.md gh pr comment "$PR_NUM" --repo "${{ github.repository }}" --body \ - "Issue #${ISSUE_NUMBER} has been triaged. The linked issue check is being re-evaluated." + "Issue #${ISSUE_NUMBER} ${EVENT_DESCRIPTION}. The linked issue check is being re-evaluated." done diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 32f86f7..8b7882a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,7 +11,7 @@ External contributors are expected to open a GitHub issue before opening a pull 3. Wait for a maintainer to apply the `triaged` label before beginning implementation. 4. Link the pull request to the open, triaged issue with `Fixes #NNN` or `Closes #NNN`. -Pull requests from external contributors should link to an open, triaged issue. The linked-issue workflow reports when this policy is not met; repository rules must separately require `Linked Issue Check / check` for that result to block merging. Repository collaborators may open pull requests directly for routine maintenance and already-planned work. +Pull requests from external contributors should link to an open, triaged issue. The linked-issue workflow reports when this policy is not met and rechecks when the selected issue gains or loses the `triaged` label, is closed, or is reopened; repository rules must separately require `Linked Issue Check / check` for that result to block merging. Repository collaborators may open pull requests directly for routine maintenance and already-planned work. ## Preparing Your Change From d385f83eb76093c5ed487c33d5c97a71daea59a2 Mon Sep 17 00:00:00 2001 From: Nabin Mulepati Date: Thu, 27 Aug 2026 11:23:38 -0600 Subject: [PATCH 6/6] fix: rerun linked issue checks directly Signed-off-by: Nabin Mulepati --- .github/workflows/pr-linked-issue.yml | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/.github/workflows/pr-linked-issue.yml b/.github/workflows/pr-linked-issue.yml index c2b95c8..7d328df 100644 --- a/.github/workflows/pr-linked-issue.yml +++ b/.github/workflows/pr-linked-issue.yml @@ -14,6 +14,7 @@ on: types: [labeled, unlabeled, closed, reopened] permissions: + actions: write contents: read pull-requests: write issues: read @@ -257,8 +258,6 @@ jobs: ISSUE_NUMBER: ${{ github.event.issue.number }} PR_NUMBERS: ${{ steps.find-prs.outputs.prs }} run: | - TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ) - case "$ISSUE_ACTION" in labeled) EVENT_DESCRIPTION='received the `triaged` label' @@ -281,18 +280,22 @@ jobs: for PR_NUM in $PR_NUMBERS; do echo "Re-triggering check for PR #${PR_NUM}..." - gh pr view "$PR_NUM" --repo "${{ github.repository }}" --json body -q '.body' > /tmp/current-body.txt - - MARKER="||" \ - /tmp/current-body.txt > /tmp/pr-body.md - else - cp /tmp/current-body.txt /tmp/pr-body.md - printf '\n' "$TIMESTAMP" >> /tmp/pr-body.md + # Find the latest completed run for this PR's current head commit. + # Editing the PR with the workflow's GITHUB_TOKEN would not trigger + # another workflow run. + HEAD_SHA=$(gh pr view "$PR_NUM" --repo "${{ github.repository }}" \ + --json headRefOid --jq '.headRefOid') + RUN_ID=$(gh run list --repo "${{ github.repository }}" \ + --workflow pr-linked-issue.yml --event pull_request_target \ + --commit "$HEAD_SHA" --status completed --limit 1 \ + --json databaseId --jq '.[0].databaseId') + + if [ -z "$RUN_ID" ]; then + echo "::warning::No completed Linked Issue Check run found for PR #${PR_NUM}" + continue fi - gh pr edit "$PR_NUM" --repo "${{ github.repository }}" --body-file /tmp/pr-body.md + gh run rerun "$RUN_ID" --repo "${{ github.repository }}" gh pr comment "$PR_NUM" --repo "${{ github.repository }}" --body \ "Issue #${ISSUE_NUMBER} ${EVENT_DESCRIPTION}. The linked issue check is being re-evaluated." done