Skip to content

misc: Update pr-issue-validator.yaml #9354

misc: Update pr-issue-validator.yaml

misc: Update pr-issue-validator.yaml #9354

name: Validate Pull Request
on:
pull_request:
types:
- opened
- synchronize
- edited
- reopened
branches:
- 'main'
- 'release-**'
- 'develop'
# paths-ignore:
# - 'docs/**'
# - '.github/'
# - 'CHANGELOG/'
# - 'charts/'
# - 'manifests/'
# - 'sample-docker-templates/'
jobs:
validate-PR-issue:
runs-on: ubuntu-latest
permissions:
issues: write
contents: read
pull-requests: write
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0
- name: Validate Issue Reference
env:
GITHUB_TOKEN: ${{ github.token }}
PR_BODY: ${{ github.event.pull_request.body }}
url: ${{ github.event.pull_request.url }}
PRNUM: ${{ github.event.pull_request.number }}
TITLE: ${{ github.event.pull_request.title }}
run: |
set -ex
echo "base or target repo : ${{ github.event.pull_request.base.repo.full_name }}"
echo "head or source repo : ${{ github.event.pull_request.head.repo.full_name }}"
if [[ ${{ github.event.pull_request.head.repo.full_name }} == ${{ github.event.pull_request.base.repo.full_name }} ]]; then
export forked=false
else
export forked=true
fi
echo "forked: $forked"
if [[ "$TITLE" == *"doc:"* || "$TITLE" == *"docs:"* || "$TITLE" == *"misc:"* || "$TITLE" == *"release:"* || "$TITLE" == *"Release:"* ]]; then
echo "Skipping validation as this is a PR for documentation or misc."
if [[ $forked == true ]]; then
echo "PR:Ready-to-Review, exiting gracefully"
exit 0
fi
gh pr edit $PRNUM --remove-label "PR:Issue-verification-failed"
gh pr edit $PRNUM --add-label "PR:Ready-to-Review"
exit 0
fi
### For ex: Fixes #2123
### For ex: Fixes: #2123
pattern1="((Fixes|Resolves):? #[0-9]+)"
### For ex: Resolves https://github.com/devtron-labs/devtron/issues/2123
pattern2="((Fixes|Resolves):? https://github.com/devtron-labs/devtron/issues/[0-9]+)"
### For ex: Fixes devtron-labs/devtron#2123
pattern3="((Fixes|Resolves):? devtron-labs/devtron#[0-9]+)"
### For ex: Fixes [#4839](https://github.com/devtron-labs/devtron/issues/4839)
pattern4="(Fixes|Resolves):?\s+\[#([0-9]+)\]"
# Get the pull request body
PR_BODY=$(jq -r '.pull_request.body' $GITHUB_EVENT_PATH)
echo "PR_BODY = $PR_BODY"
### Checks if PR_BODY matches pattern1 or pattern2 or pattern3 or none
### grep -i (case insensitive) -E (enables extended regular expression in grep) -q (this option suppresses normal output)
if echo "$PR_BODY" | grep -iEq "$pattern1"; then
### Here we are taking only the numerical value ie. issue number
### head -n1 only prints the 1st line.
### grep -o -E "[0-9]+ basically outputs only the number between [0-9]+
echo "$PR_BODY" | grep -iE "$pattern1" | head -n1 | grep -o -E "[0-9]+" | tr -d '\r\n' > issue_num
issue_num=$(cat issue_num)
echo "issue_num is : $issue_num"
elif echo "$PR_BODY" | grep -iEq "$pattern2"; then
echo "$PR_BODY" | grep -iE "$pattern2" | head -n1 | awk -F '/' '{print $NF}' | tr -d '\r\n' > issue_num
issue_num=$(cat issue_num)
echo "issue_num is : $issue_num"
elif echo "$PR_BODY" | grep -iEq "$pattern3"; then
echo "$PR_BODY" | grep -iE "$pattern3" | head -n1 | awk -F '#' '{print $NF}' | tr -d '\r\n' > issue_num
issue_num=$(cat issue_num)
echo "issue_num is : $issue_num"
elif echo "$PR_BODY" | grep -iEq "$pattern4"; then
echo "$PR_BODY" | grep -oP "$pattern4" | head -n1 | grep -oP '#\K[0-9]+' | tr -d '\r\n' > issue_num
issue_num=$(cat issue_num)
echo "issue_num is : $issue_num"
else
echo "No Issue number detected hence failing the PR Validation check."
if [[ $forked == true ]]; then
echo "PR:Issue-verification-failed, exiting forcefully!"
exit 1
fi
gh pr edit $PRNUM --add-label "PR:Issue-verification-failed"
gh pr edit $PRNUM --remove-label "PR:Ready-to-Review"
exit 1
fi
### Here we are setting the Internal Field Separator to "/"
### read -r -> reads input from variable $url
### -a url_parts -> tells read command to store input into an array named url_parts[]
IFS="/" read -r -a url_parts <<< "$url"
# Remove the last two elements (repos and the issue number)
unset url_parts[-1]
unset url_parts[-1]
# Reattach the URL pieces
url=$(IFS=/; echo "${url_parts[*]}")
# Add the issue number to the URL
url="${url}/issues/${issue_num}"
echo "$url"
response_code=$(curl -s -o /dev/null -w "%{http_code}" "$url")
if [[ "$response_code" -eq 200 ]]; then
# Check if issue is open or closed
text=$(curl -s "$url")
echo "checking status of the issue"
if [[ $(echo "$text" | jq -r '.state') == "open" ]]; then
echo "Issue #$issue_num is open"
echo "Issue reference found in the pull request body."
if [[ $forked == true ]]; then
echo "PR:Ready-to-Review, exiting gracefully"
exit 0
fi
gh pr edit $PRNUM --remove-label "PR:Issue-verification-failed"
gh pr edit $PRNUM --add-label "PR:Ready-to-Review"
exit 0
else
echo "Issue #$issue_num is not open"
if [[ $forked == true ]]; then
echo "PR:Issue-verification-failed, exiting forcefully!"
exit 1
fi
gh pr edit $PRNUM --add-label "PR:Issue-verification-failed"
gh pr edit $PRNUM --remove-label "PR:Ready-to-Review"
exit 1
fi
else
echo "Invalid Response Code obtained - error code: $response_code"
echo "No valid issue reference found in the pull request body."
gh pr comment $PRNUM --body "PR is not linked to any issue, please make the corresponding changes in the body."
if [[ $forked == true ]]; then
echo "PR:Issue-verification-failed, exiting forcefully!"
exit 1
fi
gh pr edit $PRNUM --add-label "PR:Issue-verification-failed"
gh pr edit $PRNUM --remove-label "PR:Ready-to-Review"
exit 1
fi
- name: Check SQL file format and duplicates
shell: bash
env:
pr_no: ${{ github.event.pull_request.number }}
GH_TOKEN: ${{ github.token }}
run: |
set -ex
# Fetch the latest changes from the main branch
git fetch origin main
# Get the list of changed files
git diff origin/main...HEAD --name-only > diff
# Specify the directory containing migration files
MIGRATION_DIR="scripts/sql"
# Print changed files
echo "Changed files:"
cat diff
# Extract relevant .up.sql migration files from the changed files list
changed_files=$(grep "^$MIGRATION_DIR/" diff | grep -E "\.up\.sql$")
# Check if there are any .up.sql migration files in the changed files list
if [ -z "$changed_files" ]; then
echo "No .up.sql migration files found in the changes."
else
# Extract unique migration numbers from the directory (considering only .up.sql files)
existing_migrations=$(ls $MIGRATION_DIR | grep -E "\.up\.sql$" | grep -oE "[0-9]{3}[0-9]{3}[0-9]{2}" | sort | uniq)
# Exclude migration numbers from changed files in existing_migrations
while read -r file; do
migration_number=$(basename "$file" | grep -oE "[0-9]{3}[0-9]{3}[0-9]{2}")
existing_migrations=$(echo "$existing_migrations" | grep -v "$migration_number")
done <<< "$changed_files"
# Validate each changed .up.sql migration file
is_valid=true
processed_migrations=()
while read -r file; do
# Extract migration number from the filename
migration_number=$(basename "$file" | grep -oE "[0-9]{3}[0-9]{3}[0-9]{2}")
# Check if the filename has the full XXXPPPNN format
if [[ ! $(basename "$file") =~ ^[0-9]{3}[0-9]{3}[0-9]{2}_ ]]; then
echo "Error: Migration file $file does not have the complete XXXPPPNN format."
is_valid=false
continue
fi
if [ -z "$migration_number" ]; then
echo "Warning: Could not extract migration number from $file."
continue
fi
# Check if this migration number has already been processed
if [[ " ${processed_migrations[@]} " =~ " $migration_number " ]]; then
continue
fi
processed_migrations+=("$migration_number")
# Check if the migration number is unique
if echo "$existing_migrations" | grep -q "$migration_number"; then
echo "Error: Migration number $migration_number already exists."
is_valid=false
fi
# Check if the migration number is greater than previous ones
last_migration=$(echo "$existing_migrations" | tail -n 1)
if [ "$migration_number" -le "$last_migration" ]; then
echo "Error: Migration number $migration_number is not greater than the latest ($last_migration)."
is_valid=false
fi
# Check for sequential hotfix requirement (if NN > 01, check for NN-1)
hotfix_number=$(echo "$migration_number" | grep -oE "[0-9]{2}$")
if [ "$hotfix_number" -gt "01" ]; then
previous_hotfix=$(printf "%02d" $((10#$hotfix_number - 1)))
expected_previous_number="${migration_number:0:6}$previous_hotfix"
if ! echo "$existing_migrations" | grep -q "$expected_previous_number"; then
echo "Error: Previous hotfix migration $expected_previous_number not found for $migration_number."
is_valid=false
fi
fi
done <<< "$changed_files"
if [ "$is_valid" = false ]; then
echo "Validation failed. Please fix the errors before merging."
gh pr comment $pr_no --body "The Migration files providede inside of the PR does not pass the criteria!!"
exit 1
fi
echo "All .up.sql migration file validations passed."
gh pr comment $pr_no --body "The migration files have successfully passed the criteria!!"
fi