Skip to content

Commit 5dcdcd6

Browse files
committed
.github/workflows: Add PR formatting validator
This workflow runs when GitHub PRs are modified (edited, opened, reopened, and synchronized) to perform basic validation of the PR title and description. Right now, this includes: - Checking that PR template text does not remain in the PR description. - Checking that the PR body is not empty. If a check fails, a GitHub comment will be left on the PR and a PR status check failure will be present on the PR until the issue is resolved. Signed-off-by: Michael Kubacki <[email protected]>
1 parent 2ff173a commit 5dcdcd6

File tree

1 file changed

+153
-0
lines changed

1 file changed

+153
-0
lines changed
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
# This workflow validates basic pull request formatting requirements are met.
2+
#
3+
# Copyright (c) Microsoft Corporation.
4+
# SPDX-License-Identifier: BSD-2-Clause-Patent
5+
6+
name: Validate Pull Request Formatting
7+
8+
on:
9+
pull_request_target:
10+
branches:
11+
- add_pr_formatting_val_workflow_test_target
12+
types:
13+
- edited
14+
- opened
15+
- reopened
16+
- synchronize
17+
18+
concurrency:
19+
group: pr-validation-${{ github.event.number }}
20+
cancel-in-progress: true
21+
22+
permissions:
23+
contents: read
24+
pull-requests: write
25+
26+
jobs:
27+
validate_pr:
28+
name: Validate Pull Request Formatting
29+
runs-on: ubuntu-latest
30+
31+
steps:
32+
- name: Validate PR Format
33+
id: validate
34+
run: |
35+
# Constants
36+
readonly VALIDATION_HEADER="Pull Request Formatting Issues"
37+
38+
# Fetch PR data
39+
prData="$(gh api graphql -F owner=$OWNER -F name=$REPO -F pr_number=$PR_NUMBER -f query='
40+
query($name: String!, $owner: String!, $pr_number: Int!) {
41+
repository(owner: $owner, name: $name) {
42+
pullRequest(number: $pr_number) {
43+
title
44+
body
45+
}
46+
}
47+
}')"
48+
49+
prTitle=$(echo "$prData" | jq -r '.data.repository.pullRequest.title // ""')
50+
prBody=$(echo "$prData" | jq -r '.data.repository.pullRequest.body // ""')
51+
52+
# Fetch template content (may not exist)
53+
templateContent=""
54+
if gh api repos/$GITHUB_REPOSITORY/contents/.github/pull_request_template.md > /dev/null 2>&1; then
55+
templateContent="$(gh api repos/$GITHUB_REPOSITORY/contents/.github/pull_request_template.md --jq '.content' | base64 --decode)"
56+
fi
57+
58+
validationError=false
59+
validationMessages=""
60+
61+
# Validate PR title
62+
if [[ -z "$prTitle" ]]; then
63+
validationMessages+="⚠️ Pull request title cannot be empty."$'\n'
64+
validationError=true
65+
fi
66+
67+
# Validate PR body
68+
if [[ -z "$prBody" || "$prBody" == "null" ]] || [[ -z "$(echo "$prBody" | xargs)" ]]; then
69+
validationMessages+="⚠️ Add a meaningful pull request description using the [PR template](https://github.com/tianocore/edk2/blob/master/.github/pull_request_template.md)."$'\n'
70+
validationError=true
71+
elif [[ ${#prBody} -lt 147 ]]; then
72+
validationMessages+="⚠️ Provide a more detailed pull request description using the [PR template](https://github.com/tianocore/edk2/blob/master/.github/pull_request_template.md) (current: ${#prBody} characters)."$'\n'
73+
validationError=true
74+
fi
75+
76+
# Check for template lines if template exists
77+
if [[ -n "$templateContent" ]]; then
78+
# Template lines are considered to be those that begin with '<_' and end with '_>'
79+
templateLines=$(echo "$templateContent" | grep -E '^<_.*_>$' || true)
80+
81+
if [[ -n "$templateLines" ]]; then
82+
templateLinesFound=""
83+
while IFS= read -r line; do
84+
# Use more precise matching - check for the line as a standalone line
85+
if [[ -n "$line" ]] && echo "$prBody" | grep -Fxq "$line"; then
86+
if [[ -n "$templateLinesFound" ]]; then
87+
templateLinesFound="$templateLinesFound"$'\n'"\`$line\`"
88+
else
89+
templateLinesFound="\`$line\`"
90+
fi
91+
fi
92+
done <<< "$templateLines"
93+
94+
if [[ -n "$templateLinesFound" ]]; then
95+
validationMessages+="⚠️ Remove the following template lines from your PR description:"$'\n'"$templateLinesFound"$'\n'
96+
validationError=true
97+
fi
98+
fi
99+
fi
100+
101+
# Output validation results
102+
echo "validation_error=$validationError" >> $GITHUB_OUTPUT
103+
if [[ "$validationError" == "true" ]]; then
104+
echo "VALIDATION_MESSAGES<<EOF" >> $GITHUB_ENV
105+
echo "$validationMessages" >> $GITHUB_ENV
106+
echo "EOF" >> $GITHUB_ENV
107+
echo "VALIDATION_HEADER=$VALIDATION_HEADER" >> $GITHUB_ENV
108+
fi
109+
env:
110+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
111+
OWNER: ${{ github.repository_owner }}
112+
PR_NUMBER: ${{ github.event.number }}
113+
REPO: ${{ github.event.pull_request.base.repo.name }}
114+
115+
- name: Post Validation Comment
116+
if: steps.validate.outputs.validation_error == 'true'
117+
run: |
118+
# Create comment body
119+
commentBody="## $VALIDATION_HEADER"$'\n\n'"$VALIDATION_MESSAGES"$'\n'"Address these issues and the validation will automatically re-run when you update your pull request."
120+
121+
# Create validation hash for duplicate detection
122+
validationHash=$(echo "$VALIDATION_MESSAGES" | sha256sum | cut -d' ' -f1)
123+
commentBodyWithHash="$commentBody"$'\n\n'"<!-- validation-hash: $validationHash -->"
124+
125+
# Check if a comment with same validation hash already exists
126+
existingComments=$(gh pr view $PR_NUMBER --repo $GITHUB_REPOSITORY --json comments --jq '.comments[] | select(.body | contains("Pull Request Formatting Issues")) | .body')
127+
128+
duplicateFound=false
129+
if [[ -n "$existingComments" ]]; then
130+
while IFS= read -r comment; do
131+
if [[ "$comment" == *"validation-hash: $validationHash"* ]]; then
132+
duplicateFound=true
133+
break
134+
fi
135+
done <<< "$existingComments"
136+
fi
137+
138+
if [[ "$duplicateFound" == "false" ]]; then
139+
gh pr comment $PR_NUMBER --repo $GITHUB_REPOSITORY --body "$commentBodyWithHash"
140+
echo "Posted validation comment (hash: $validationHash)"
141+
else
142+
echo "Skipped posting duplicate validation comment (hash: $validationHash)"
143+
fi
144+
env:
145+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
146+
PR_NUMBER: ${{ github.event.number }}
147+
148+
- name: Check for Validation Errors
149+
if: steps.validate.outputs.validation_error == 'true'
150+
uses: actions/github-script@v7
151+
with:
152+
script: |
153+
core.setFailed('PR Formatting Validation Check Failed!')

0 commit comments

Comments
 (0)