From dfe367ef8661e4b07be4c45fb1d324798edf343c Mon Sep 17 00:00:00 2001 From: "Lytovchenko, Danylo" Date: Wed, 28 May 2025 10:09:53 +0200 Subject: [PATCH] SWDEV-123456 - add validation workflows (#96) [ROCm/hip commit: 893718cdd772126d50c533d63fae05f4a339d7f8] --- .../scripts/validate_pr_description.py | 76 +++++++++++++++++++ .../hip/.github/workflows/keyword-check.yml | 73 ++++++++++++++++++ .../.github/workflows/pr-title-validate.yml | 42 ++++++++++ .../workflows/validate-pr-description.yml | 22 ++++++ 4 files changed, 213 insertions(+) create mode 100644 projects/hip/.github/scripts/validate_pr_description.py create mode 100644 projects/hip/.github/workflows/keyword-check.yml create mode 100644 projects/hip/.github/workflows/pr-title-validate.yml create mode 100644 projects/hip/.github/workflows/validate-pr-description.yml diff --git a/projects/hip/.github/scripts/validate_pr_description.py b/projects/hip/.github/scripts/validate_pr_description.py new file mode 100644 index 0000000000..eb282acffd --- /dev/null +++ b/projects/hip/.github/scripts/validate_pr_description.py @@ -0,0 +1,76 @@ +import os, re, sys +from typing import List, Optional + + +def is_checkbox(line: str) -> bool: + return bool(re.match(r"^\s*-\s*\[[ xX]\]\s*.+", line)) + + +def is_checked(line: str) -> bool: + return bool(re.match(r"^\s*-\s*\[[xX]\]\s*.+", line)) + + +def is_comment(line: str) -> bool: + return bool(re.match(r"^\s*\s*$", line)) + + +def text_clean(lines: List[str]) -> str: + text = [line for line in lines if not is_comment(line)] + return "".join("".join(text).strip().split()) + + +def validate_section(section_name: str, lines: List[str]) -> Optional[str]: + has_checkboxes = any(is_checkbox(line) for line in lines) + if has_checkboxes: + if not any(is_checked(line) for line in lines): + return f"Section {section_name} is a checklist without selections" + return None + if not text_clean(lines): + return f"Section {section_name} is empty text section" + return None + + +def check_description(description: str) -> List[str]: + if not description: + # pull_request_template is not merged yet, so treat as valid for now + return [] + # return ["PR description is empty"] + + sections = [] + current_section = None + current_lines = [] + errors = [] + + for line in description.splitlines(): + header_match = re.match(r"^\s*##\s*(.+?)\s*$", line) + if header_match: + if current_section: + sections.append((current_section, current_lines)) + current_section = header_match.group(1) + current_lines = [] + elif current_section: + current_lines.append(line) + + if current_section: + sections.append((current_section, current_lines)) + + if not sections: + return ["No sections available, template is empty"] + + for section_name, section_lines in sections: + error = validate_section(section_name, section_lines) + if error: + errors.append(error) + + return errors + + +if __name__ == "__main__": + pr_description = os.getenv("PR_DESCRIPTION", "") + + errors = check_description(pr_description) + if not errors: + print("All good") + exit(0) + print("\n".join(errors)) + exit(1) diff --git a/projects/hip/.github/workflows/keyword-check.yml b/projects/hip/.github/workflows/keyword-check.yml new file mode 100644 index 0000000000..7177d1a669 --- /dev/null +++ b/projects/hip/.github/workflows/keyword-check.yml @@ -0,0 +1,73 @@ +name: Keywords checker + +on: + pull_request: + types: [opened, synchronize, reopened, edited] + branches: + - amd-staging + workflow_dispatch: + +jobs: + check-keywords: + runs-on: ubuntu-latest + env: + KEYWORDS: ${{ vars.KEYWORDS }} + + steps: + - name: Checkout code + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Check keywords + run: | + set -e + + if [ -z "$KEYWORDS" ]; then + echo "No keywords set. Skipping check" + exit 0 + fi + + IFS=',' read -ra KEYWORDS_ARRAY <<< "$KEYWORDS" + echo "Checking against list of keywords: ${KEYWORDS_ARRAY[*]}" + + MATCHED=0 + BASE_BRANCH=${{github.event.pull_request.base.ref}} + HEAD_BRANCH=${{github.event.pull_request.head.ref}} + PR_TITLE="${{ github.event.pull_request.title }}" + + for file in $(git diff --name-only origin/$BASE_BRANCH..origin/$HEAD_BRANCH); do + if [ -f "$file" ]; then + for keyword in "${KEYWORDS_ARRAY[*]}"; do + grep -in -E "${keyword}" "$file" | while IFS= read -r line; do + echo "Matched in '$file': $line" + MATCHED=1 + done + done + fi + done + + for commit in $(git log --format=%H origin/$BASE_BRANCH..origin/$HEAD_BRANCH); do + msg=$(git log -1 --format=%B "$commit") + for keyword in "${KEYWORDS_ARRAY[*]}"; do + if echo "$msg" | grep -i -q "$keyword"; then + echo "Match in commit $commit: $msg" + MATCHED=1 + fi + done + done + + for keyword in "${KEYWORDS_ARRAY[*]}"; do + if echo "$PR_TITLE" | grep -i -q "$keyword"; then + echo "Match in PR title" + MATCHED=1 + fi + done + + if [ "$MATCHED" -eq 1 ]; then + echo "Keywords found, please see diagnostics higher" + exit 1 + else + echo "No keywords found" + exit 0 + fi diff --git a/projects/hip/.github/workflows/pr-title-validate.yml b/projects/hip/.github/workflows/pr-title-validate.yml new file mode 100644 index 0000000000..65f5564d81 --- /dev/null +++ b/projects/hip/.github/workflows/pr-title-validate.yml @@ -0,0 +1,42 @@ +name: Validate PR Title + +on: + pull_request: + types: [opened, edited, synchronize, reopened] + +jobs: + validate-pr-title: + runs-on: ubuntu-latest + steps: + - name: Check PR Title + id: check-pr-title + run: | + PR_TITLE="${{ github.event.pull_request.title }}" + + if [[ ! "$PR_TITLE" =~ ^SWDEV-[0-9]+ ]]; then + echo "::error::PR title must start with a Jira ticket ID, SWDEV-" + exit 1 + else + echo "PR title is valid" + fi + + validate-commit-messages: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Check all commit messages + id: validate-commit-messags + run: | + COMMITS=$(git log --format="%H %s" origin/${{ github.event.pull_request.base.ref }}..origin/${{ github.event.pull_request.head.ref }}) + echo "$COMMITS" + echo "$COMMITS" | while read -r hash message; do + echo -e "$hash $message\n " + if [[ ! "$message" =~ ^SWDEV-[0-9]+ ]]; then + echo "::error:: $hash commit should start with Jira ticket ID, SWDEV-" + exit 1 + fi + done diff --git a/projects/hip/.github/workflows/validate-pr-description.yml b/projects/hip/.github/workflows/validate-pr-description.yml new file mode 100644 index 0000000000..db69802d81 --- /dev/null +++ b/projects/hip/.github/workflows/validate-pr-description.yml @@ -0,0 +1,22 @@ +name: Validate PR desription + +on: + pull_request: + types: [opened, edited, synchronize] + +jobs: + validate-pr-description: + 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.13" + + - name: Validate PR description + env: + PR_DESCRIPTION: ${{ github.event.pull_request.body }} + run: python .github/scripts/validate_pr_description.py