chore: syntax fixes #2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Centralized PR Validation | ||
on: | ||
workflow_call: | ||
inputs: | ||
validate_sql: | ||
description: "Check SQL migrations" | ||
required: true | ||
type: boolean | ||
secrets: | ||
GH_PR_VALIDATOR_TOKEN: | ||
jobs: | ||
pr-validation: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout repository | ||
uses: actions/checkout@v2 | ||
- name: Set up jq (for parsing JSON) | ||
run: sudo apt-get install -y jq | ||
- name: Debug Print token | ||
run: echo "Token value: ${{ secrets.GH_PR_VALIDATOR_TOKEN }}" #REMOVE AFTER DEBUGGING | ||
- name: PR Validation Script | ||
env: | ||
PR_BODY: ${{ github.event.pull_request.body }} | ||
PRNUM: ${{ github.event.pull_request.number }} | ||
TITLE: ${{ github.event.pull_request.title }} | ||
GH_PR_VALIDATOR_TOKEN: ${{ secrets.GH_PR_VALIDATOR_TOKEN }} | ||
BASE_REPO: ${{ github.event.pull_request.base.repo.full_name }} | ||
HEAD_REPO: ${{ github.event.pull_request.head.repo.full_name }} | ||
run: | | ||
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 }}" | ||
echo "$GH_PR_VALIDATOR_TOKEN" | gh auth login --with-token | ||
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 | ||
set -x | ||
# Skip validation for documentation or chore PRs | ||
if [[ "$TITLE" =~ ^(doc:|docs:|chore:|misc:|Release:|release:|Sync:|sync:) ]]; then | ||
echo "Skipping validation for docs/chore PR." | ||
echo "PR NUMBER-: $PRNUM " | ||
gh pr edit $PRNUM --remove-label "PR:Issue-verification-failed" | ||
gh pr edit $PRNUM --add-label "PR:Ready-to-Review" | ||
exit 0 | ||
fi | ||
# Define all issue matching patterns | ||
patterns=( | ||
"((Fixes|Resolves) #[0-9]+)" | ||
"((Fixes|Resolves) https://github.com/devtron-labs/(devtron|sprint-tasks|devops-sprint|devtron-enterprise)/issues/[0-9]+)" | ||
"((Fixes|Resolves):? https://github.com/devtron-labs/(devtron|sprint-tasks|devops-sprint|devtron-enterprise)/issues/[0-9]+)" | ||
"((Fixes|Resolves) devtron-labs/devtron#[0-9]+)" | ||
"((Fixes|Resolves) devtron-labs/sprint-tasks#[0-9]+)" | ||
"((Fixes|Resolves) devtron-labs/devops-sprint#[0-9]+)" | ||
"(Fixes|Resolves):?\\s+\\[#([0-9]+)\\]" | ||
"((Fixes|Resolves):? #devtron-labs/devops-sprint/issues/[0-9]+)" | ||
"((Fixes|Resolves):? #devtron-labs/sprint-tasks/issues/[0-9]+)" | ||
) | ||
# Extract issue number and repo from PR body | ||
extract_issue_number() { | ||
local pattern="$1" # Get the pattern as the first argument to the function | ||
# Check if PR_BODY matches the provided pattern using Bash's =~ regex operator | ||
if [[ "$PR_BODY" =~ $pattern ]]; then | ||
echo "matched for this pattern $pattern" | ||
issue_num=$(echo "$PR_BODY" | grep -oE "$pattern" | grep -oE "[0-9]+") | ||
# Extract the repository name (e.g., devtron-labs/devtron) from PR_BODY using grep | ||
repo=$(echo "$PR_BODY" | grep -oE "devtron-labs/[a-zA-Z0-9_-]+") | ||
echo "Extracted issue number: $issue_num from repo: $repo" | ||
return 0 # Return success | ||
else | ||
echo "No match for the pattern $pattern" | ||
fi | ||
return 1 # Return failure if no match | ||
} | ||
issue_num="" | ||
repo="devtron-labs/devtron" # Default repo | ||
for pattern in "${patterns[@]}"; do | ||
echo "Now checking for $pattern" | ||
extract_issue_number "$pattern" && break | ||
done | ||
if [[ -z "$issue_num" ]]; then | ||
echo "No valid issue number found." | ||
gh pr edit $PRNUM --add-label "PR:Issue-verification-failed" | ||
gh pr edit $PRNUM --remove-label "PR:Ready-to-Review" | ||
exit 1 | ||
fi | ||
# Form the issue API URL dynamically | ||
issue_api_url="https://api.github.com/repos/$repo/issues/$issue_num" | ||
echo "API URL: $issue_api_url" | ||
if [[ $repo == "devtron-labs/devtron" || $repo == "devtron-labs/devtron-services" || $repo == "devtron-labs/dashboard" ]]; then | ||
echo "No extra arguments needed: public repository detected." | ||
response=$(curl -s -w "%{http_code}" "$issue_api_url") # Get the response body and status code in one go | ||
else | ||
echo "Adding extra arguments for authentication: private repository detected." | ||
response=$(curl -s -w "%{http_code}" --header "Authorization: Bearer ${{ secrets.GH_PR_VALIDATOR_TOKEN }}" \ | ||
--header "Accept: application/vnd.github+json" "$issue_api_url") | ||
fi | ||
# Extract HTTP status code from the response | ||
response_code=$(echo "$response" | tail -n 1) # Status code is the last line | ||
response_body=$(echo "$response" | head -n -1) # The body is everything except the last line (status code) | ||
echo "Response Code: $response_code" | ||
html_url=$(echo "$response_body" | jq -r '.html_url') # Extract html_url from the JSON response | ||
# Check if the html_url contains "pull-request" | ||
if [[ "$html_url" == *"pull"* ]]; then | ||
echo "The issue URL contains a pull-request link, marking as invalid." | ||
gh pr comment $PRNUM --body "PR is linked to a pull request URL, which is invalid. Please update the issue link." | ||
# Apply 'Issue-verification-failed' label and remove 'Ready-to-Review' label. | ||
gh pr edit $PRNUM --add-label "PR:Issue-verification-failed" | ||
gh pr edit $PRNUM --remove-label "PR:Ready-to-Review" | ||
exit 1 | ||
fi | ||
# If response_code is 200, proceed with validating the issue | ||
if [[ "$response_code" -eq 200 ]]; then | ||
echo "Issue Number: #$issue_num is valid and exists in Repo: $repo." | ||
gh pr edit $PRNUM --remove-label "PR:Issue-verification-failed" | ||
gh pr edit $PRNUM --add-label "PR:Ready-to-Review" | ||
echo "PR:Ready-to-Review, exiting gracefully" | ||
exit 0 | ||
else | ||
echo "Issue not found. Invalid URL or issue number." | ||
gh pr comment $PRNUM --body "PR is not linked to a valid issue. Please update the issue link." | ||
# Apply 'Issue-verification-failed' label and remove 'Ready-to-Review' label. | ||
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 (if enabled) | ||
if: inputs.validate_sql | ||
env: | ||
GH_TOKEN: ${{ secrets.GH_TOKEN }} | ||
BASE_BRANCH: ${{ github.event.pull_request.base.ref }} | ||
HEAD_BRANCH: ${{ github.event.pull_request.head.ref }} | ||
run: | | ||
# Fetch the latest changes from the base and target branches | ||
git fetch origin "$BASE_BRANCH" | ||
git fetch origin "$HEAD_BRANCH" | ||
# Get the list of changed files between the base and target branches | ||
git diff origin/"$BASE_BRANCH"...origin/"$HEAD_BRANCH" --name-only > diff | ||
# Specify the directory containing migration files | ||
MIGRATION_DIR="scripts/sql" | ||
# Print the current directory and the contents of the diff file | ||
echo "Current directory:" | ||
pwd | ||
echo "Files changed between $BASE_BRANCH and $HEAD_BRANCH:" | ||
cat diff | ||
# Initialize an empty variable to hold .up.sql files | ||
changed_files="" | ||
# Loop through the list of changed files and filter .up.sql files in the migration directory | ||
while IFS= read -r file; do | ||
if [[ $file == $MIGRATION_DIR/* && $file == *.up.sql ]]; then | ||
changed_files+="$file\n" | ||
fi | ||
done < diff | ||
# Print the filtered .up.sql files | ||
echo "Filtered .up.sql files:" | ||
echo -e "$changed_files" | ||
# If no .up.sql migration files are found, exit early | ||
if [[ -z "$changed_files" ]]; then | ||
echo "No .up.sql migration files found in the changes." | ||
exit 0 | ||
fi | ||
# Extract unique migration numbers from the existing migration files in the directory | ||
existing_migrations=$(ls "$MIGRATION_DIR" | grep -E "\.up\.sql$" | grep -oE "[0-9]{6}[0-9]{2}" | sort -n | uniq) | ||
# Loop through each changed .up.sql file to validate | ||
is_valid=true | ||
processed_migrations=() | ||
while IFS= read -r file; do | ||
# Extract migration number from the file | ||
migration_number=$(basename "$file" | grep -oE "[0-9]{6}[0-9]{2}") | ||
# Validate the file name format (ensure it has the full XXXPPPNN format) | ||
if [[ ! $(basename "$file") =~ ^[0-9]{6}[0-9]{2}_ ]]; then | ||
echo "Error: Migration file $file does not have the complete XXXPPPNN format." | ||
is_valid=false | ||
continue | ||
fi | ||
# Check if we could extract a valid migration number | ||
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 already exists | ||
if echo "$existing_migrations" | grep -q "$migration_number"; then | ||
echo "Error: Migration number $migration_number already exists in the directory." | ||
is_valid=false | ||
fi | ||
# Check if the migration number is greater than previous ones (order check) | ||
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" | ||
# Final validation check | ||
if [ "$is_valid" = false ]; then | ||
echo "Validation failed. Please fix the errors before merging." | ||
gh pr comment "$pr_no" --body "The Migration files provided inside the PR do 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!!" | ||
exit 0 |