[TRTLLM-6822][infra] Add PR-Checklist github action and modify PR template (#6029)

Signed-off-by: Venky Ganesh <23023424+venkywonka@users.noreply.github.com>
This commit is contained in:
Venky 2025-08-27 18:45:23 -07:00 committed by GitHub
parent 8a619be828
commit f30768e70d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 152 additions and 0 deletions

View File

@ -40,6 +40,20 @@ Please explain the issue and the solution in short.
Please list clearly what are the relevant test(s) that can safeguard the changes in the PR. This helps us to ensure we have sufficient test coverage for the PR.
-->
## PR Checklist
Please review the following before submitting your PR:
- PR description clearly explains what and why. If using CodeRabbit's summary, please make sure it makes sense.
- PR Follows [TRT-LLM CODING GUIDELINES](https://github.com/NVIDIA/TensorRT-LLM/blob/main/CODING_GUIDELINES.md) to the best of your knowledge.
- Test cases are provided for new code paths (see [test instructions](https://github.com/NVIDIA/TensorRT-LLM/tree/main/tests#1-how-does-the-ci-work))
- Any new dependencies have been scanned for license and vulnerabilities
- [CODEOWNERS](https://github.com/NVIDIA/TensorRT-LLM/blob/main/.github/CODEOWNERS) updated if ownership changes
- Documentation updated as needed
- The reviewers assigned automatically/manually are appropriate for the PR.
- [ ] Please check this after reviewing the above items as appropriate for this PR.
## GitHub Bot Help
`/bot [-h] ['run', 'kill', 'skip', 'reuse-pipeline'] ...`

120
.github/scripts/pr_checklist_check.py vendored Normal file
View File

@ -0,0 +1,120 @@
#!/usr/bin/env python3
# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import re
import sys
from typing import List
# Matches a Markdown checklist item in the PR body.
# Expected format: "- [ ] Task description" or "* [x] Task description"
# Group 1 captures the checkbox state: ' ' (unchecked), 'x' or 'X' (checked).
# Group 2 captures the task content (the description of the checklist item).
TASK_PATTERN = re.compile(r'^\s*[-*]\s+\[( |x|X)\]\s*(.*)')
def find_all_tasks(pr_body: str) -> List[str]:
"""Return list of all task list items (both resolved and unresolved)."""
tasks: List[str] = []
for line in pr_body.splitlines():
match = TASK_PATTERN.match(line)
if match:
tasks.append(match.group(0).strip())
return tasks
def find_unresolved_tasks(pr_body: str) -> List[str]:
"""Return list of unresolved task list items.
A task is considered resolved if it is checked (``[x]`` or ``[X]``)
or if its text is struck through using ``~~`` markers.
"""
unresolved: List[str] = []
for line in pr_body.splitlines():
match = TASK_PATTERN.match(line)
if not match:
continue
state, content = match.groups()
if state.lower() == 'x':
continue
# Check if the entire content is struck through
if content.strip().startswith('~~') and content.strip().endswith('~~'):
continue
unresolved.append(match.group(0).strip())
return unresolved
def check_pr_checklist_section(pr_body: str) -> tuple[bool, str]:
"""Check if the PR Checklist section exists with the required final checkbox.
Returns:
tuple: (is_valid, error_message)
"""
# Check if "## PR Checklist" header exists
pr_checklist_pattern = re.compile(r'^##\s+PR\s+Checklist',
re.IGNORECASE | re.MULTILINE)
if not pr_checklist_pattern.search(pr_body):
return False, "Missing '## PR Checklist' header. Please ensure you haven't removed the PR template section."
# Check if the final checkbox exists (the one users must check)
final_checkbox_pattern = re.compile(
r'^\s*[-*]\s+\[( |x|X)\]\s+Please check this after reviewing the above items',
re.MULTILINE)
if not final_checkbox_pattern.search(pr_body):
return False, "Missing the required final checkbox '- [ ] Please check this after reviewing the above items as appropriate for this PR.' Please ensure you haven't removed this from the PR template."
return True, ""
def main() -> None:
pr_body = os.environ.get("PR_BODY", "")
enforce_checklist = os.environ.get("ENFORCE_PR_HAS_CHECKLIST",
"false").lower() == "true"
# Always check for PR Checklist section when enforcement is enabled
if enforce_checklist:
is_valid, error_msg = check_pr_checklist_section(pr_body)
if not is_valid:
print(f"Error: {error_msg}")
sys.exit(1)
all_tasks = find_all_tasks(pr_body)
unresolved = find_unresolved_tasks(pr_body)
# Check if we need to enforce the presence of at least one checklist item
if enforce_checklist and not all_tasks:
print(
"Error: PR body must contain at least one checklist item when ENFORCE_PR_HAS_CHECKLIST is enabled."
)
print(
"Expected format: - [ ] Task description or * [ ] Task description")
sys.exit(1)
# If we have tasks, check if any are unresolved
if unresolved:
print("Unresolved checklist items found:")
for item in unresolved:
print(f"{item}")
sys.exit(1)
if all_tasks:
print("All checklist items resolved.")
else:
print("No checklist items found in PR body.")
if __name__ == "__main__":
main()

View File

@ -53,3 +53,21 @@ jobs:
echo " - [#1234][doc] Update documentation"
echo " - [None][chore] Minor clean-up"
exit 1
check-pr-body-checklist:
name: Check PR Checklist Resolution
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.10'
- name: Validate PR Checklist
env:
PR_BODY: ${{ github.event.pull_request.body }}
ENFORCE_PR_HAS_CHECKLIST: true
run: python .github/scripts/pr_checklist_check.py