Skip to content

Commit 069ebb0

Browse files
authored
Merge branch 'fix/pr-validator' into pr-validator-test
2 parents d80ff8e + 0da5142 commit 069ebb0

File tree

1 file changed

+225
-0
lines changed

1 file changed

+225
-0
lines changed

.github/workflows/pr-validator.yaml

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
name: Centralized PR Validation
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
validate_sql:
7+
description: "Check SQL migrations"
8+
required: true
9+
type: boolean
10+
secrets:
11+
GH_TOKEN:
12+
required: true
13+
14+
jobs:
15+
pr-validation:
16+
runs-on: ubuntu-latest
17+
18+
steps:
19+
- name: Checkout repository
20+
uses: actions/checkout@v2
21+
22+
- name: Set up jq (for parsing JSON)
23+
run: sudo apt-get install -y jq
24+
25+
- name: PR Validation Script
26+
env:
27+
PR_BODY: ${{ github.event.pull_request.body }}
28+
PRNUM: ${{ github.event.pull_request.number }}
29+
TITLE: ${{ github.event.pull_request.title }}
30+
GH_TOKEN: ${{ secrets.GH_TOKEN }}
31+
run: |
32+
BASE_REPO="${{ github.event.pull_request.base.repo.full_name }}"
33+
HEAD_REPO="${{ github.event.pull_request.head.repo.full_name }}"
34+
FORKED=false
35+
36+
if [[ "$BASE_REPO" != "$HEAD_REPO" ]]; then
37+
FORKED=true
38+
fi
39+
40+
# Skip validation for documentation or chore PRs
41+
if [[ "$TITLE" =~ ^(doc:|docs:|chore:|misc:|Release:|release:|Sync:|sync:) ]]; then
42+
echo "Skipping validation for docs/chore PR."
43+
gh pr edit "$PRNUM" --remove-label "PR:Issue-verification-failed" --add-label "PR:Ready-to-Review"
44+
exit 0
45+
fi
46+
47+
# Define issue matching patterns
48+
PATTERNS=(
49+
"((Fixes|Resolves) #[0-9]+)"
50+
"((Fixes|Resolves) https://github.com/devtron-labs/(devtron|sprint-tasks|devops-sprint)/issues/[0-9]+)"
51+
"((Fixes|Resolves) devtron-labs/devtron#[0-9]+)"
52+
"((Fixes|Resolves) devtron-labs/sprint-tasks#[0-9]+)"
53+
"((Fixes|Resolves) devtron-labs/devops-sprint#[0-9]+)"
54+
"(Fixes|Resolves):?\\s+\\[#([0-9]+)\\]"
55+
"((Fixes|Resolves):? #devtron-labs/devops-sprint/issues/[0-9]+)"
56+
"((Fixes|Resolves):? #devtron-labs/sprint-tasks/issues/[0-9]+)"
57+
)
58+
59+
# Function to extract issue number and repo from PR body
60+
extract_issue() {
61+
for pattern in "${PATTERNS[@]}"; do
62+
if [[ "$PR_BODY" =~ $pattern ]]; then
63+
issue_num="${BASH_REMATCH[0]}"
64+
issue_num=$(echo "$issue_num" | grep -oE '[0-9]+')
65+
repo=$(echo "$PR_BODY" | grep -oE "devtron-labs/[a-zA-Z0-9_-]+")
66+
echo "Found issue #$issue_num in repo: $repo"
67+
return 0
68+
fi
69+
done
70+
return 1
71+
}
72+
73+
# Extract issue number and repo
74+
extract_issue || {
75+
echo "No valid issue number found."
76+
gh pr edit "$PRNUM" --add-label "PR:Issue-verification-failed" --remove-label "PR:Ready-to-Review"
77+
exit 1
78+
}
79+
80+
# Form the issue API URL dynamically
81+
ISSUE_API_URL="https://api.github.com/repos/$repo/issues/$issue_num"
82+
83+
# Fetch issue details with curl
84+
fetch_issue_status() {
85+
local url="$1"
86+
echo "url -> $url"
87+
if [[ "$repo" == "devtron-labs/devtron" || "$repo" == "devtron-labs/devtron-services" || "$repo" == "devtron-labs/dashboard" ]]; then
88+
status_code=$(curl -s -o /dev/null -w "%{http_code}" "$url")
89+
else
90+
status_code=$(curl -s -o /dev/null -w "%{http_code}" --header "Authorization: Bearer ${{ secrets.GH_PR_VALIDATOR_TOKEN }}" "$url")
91+
fi
92+
}
93+
94+
# Get the issue response code
95+
fetch_issue_status "$ISSUE_API_URL"
96+
97+
echo "STATUS CODE: $status_code"
98+
# Handle response based on status code
99+
if [[ "$status_code" -eq 200 ]]; then
100+
echo "Issue #$issue_num exists in $repo."
101+
102+
# Add labels based on forked status and issue validity
103+
if [[ "$FORKED" == true ]]; then
104+
gh pr edit "$PRNUM" --remove-label "PR:Issue-verification-failed" --add-label "PR:Ready-to-Review"
105+
exit 0
106+
fi
107+
gh pr edit "$PRNUM" --remove-label "PR:Issue-verification-failed" --add-label "PR:Ready-to-Review"
108+
exit 0
109+
else
110+
echo "Issue not found. Invalid URL or issue number."
111+
gh pr comment "$PRNUM" --body "PR is not linked to a valid issue. Please update the issue link."
112+
gh pr edit "$PRNUM" --add-label "PR:Issue-verification-failed" --remove-label "PR:Ready-to-Review"
113+
exit 1
114+
fi
115+
116+
- name: Check SQL file format and duplicates (if enabled)
117+
if: inputs.validate_sql == true
118+
env:
119+
GH_TOKEN: ${{ secrets.GH_TOKEN }}
120+
run: |
121+
# Get the target (base) and source (head) branches
122+
BASE_BRANCH="${{ github.event.pull_request.base.ref }}"
123+
HEAD_BRANCH="${{ github.event.pull_request.head.ref }}"
124+
125+
# Fetch the latest changes from the base and target branches
126+
git fetch origin "$BASE_BRANCH"
127+
git fetch origin "$HEAD_BRANCH"
128+
129+
# Get the list of changed files between the base and target branches
130+
git diff origin/"$BASE_BRANCH"...origin/"$HEAD_BRANCH" --name-only > diff
131+
132+
# Specify the directory containing migration files
133+
MIGRATION_DIR="scripts/sql"
134+
135+
# Print the current directory and the contents of the diff file
136+
echo "Current directory:"
137+
pwd
138+
echo "Files changed between $BASE_BRANCH and $HEAD_BRANCH:"
139+
cat diff
140+
141+
# Initialize an empty variable to hold .up.sql files
142+
changed_files=""
143+
144+
# Loop through the list of changed files and filter .up.sql files in the migration directory
145+
while IFS= read -r file; do
146+
if [[ $file == $MIGRATION_DIR/* && $file == *.up.sql ]]; then
147+
changed_files+="$file\n"
148+
fi
149+
done < diff
150+
151+
# Print the filtered .up.sql files
152+
echo "Filtered .up.sql files:"
153+
echo -e "$changed_files"
154+
155+
# If no .up.sql migration files are found, exit early
156+
if [[ -z "$changed_files" ]]; then
157+
echo "No .up.sql migration files found in the changes."
158+
exit 0
159+
fi
160+
161+
# Extract unique migration numbers from the existing migration files in the directory
162+
existing_migrations=$(ls "$MIGRATION_DIR" | grep -E "\.up\.sql$" | grep -oE "[0-9]{6}[0-9]{2}" | sort -n | uniq)
163+
164+
# Loop through each changed .up.sql file to validate
165+
is_valid=true
166+
processed_migrations=()
167+
while IFS= read -r file; do
168+
# Extract migration number from the file
169+
migration_number=$(basename "$file" | grep -oE "[0-9]{6}[0-9]{2}")
170+
171+
# Validate the file name format (ensure it has the full XXXPPPNN format)
172+
if [[ ! $(basename "$file") =~ ^[0-9]{6}[0-9]{2}_ ]]; then
173+
echo "Error: Migration file $file does not have the complete XXXPPPNN format."
174+
is_valid=false
175+
continue
176+
fi
177+
178+
# Check if we could extract a valid migration number
179+
if [[ -z "$migration_number" ]]; then
180+
echo "Warning: Could not extract migration number from $file."
181+
continue
182+
fi
183+
184+
# Check if this migration number has already been processed
185+
if [[ " ${processed_migrations[@]} " =~ " $migration_number " ]]; then
186+
continue
187+
fi
188+
processed_migrations+=("$migration_number")
189+
190+
# Check if the migration number already exists
191+
if echo "$existing_migrations" | grep -q "$migration_number"; then
192+
echo "Error: Migration number $migration_number already exists in the directory."
193+
is_valid=false
194+
fi
195+
196+
# Check if the migration number is greater than previous ones (order check)
197+
last_migration=$(echo "$existing_migrations" | tail -n 1)
198+
if [[ "$migration_number" -le "$last_migration" ]]; then
199+
echo "Error: Migration number $migration_number is not greater than the latest ($last_migration)."
200+
is_valid=false
201+
fi
202+
203+
# Check for sequential hotfix requirement (if NN > 01, check for NN-1)
204+
hotfix_number=$(echo "$migration_number" | grep -oE "[0-9]{2}$")
205+
if [[ "$hotfix_number" -gt "01" ]]; then
206+
previous_hotfix=$(printf "%02d" $((10#$hotfix_number - 1)))
207+
expected_previous_number="${migration_number:0:6}$previous_hotfix"
208+
if ! echo "$existing_migrations" | grep -q "$expected_previous_number"; then
209+
echo "Error: Previous hotfix migration $expected_previous_number not found for $migration_number."
210+
is_valid=false
211+
fi
212+
fi
213+
214+
done <<< "$changed_files"
215+
216+
# Final validation check
217+
if [ "$is_valid" = false ]; then
218+
echo "Validation failed. Please fix the errors before merging."
219+
gh pr comment "$pr_no" --body "The Migration files provided inside the PR do not pass the criteria!!"
220+
exit 1
221+
fi
222+
223+
echo "All .up.sql migration file validations passed."
224+
gh pr comment "$pr_no" --body "The migration files have successfully passed the criteria!!"
225+
exit 0

0 commit comments

Comments
 (0)