Update github workflow

This commit is contained in:
acx10
2025-12-24 00:07:20 -07:00
parent 85cc819369
commit eaa8e46124
5 changed files with 63 additions and 310 deletions

View File

@@ -1,70 +0,0 @@
#!/bin/bash
# Exit immediately if a command exits with a non-zero status.
set -e
# Exit if any command in a pipeline fails, not just the last one.
set -o pipefail
# Define the path where Flyway migration files are stored.
MIGRATION_PATH="booklore-api/src/main/resources/db/migration"
# Get ALL changes: Added (A), Modified (M), Renamed (R), Copied (C), Deleted (D)
# for SQL files in the migration path between the comparison ref and the current HEAD.
# The output is saved to a temporary file for further processing.
git diff --name-status --diff-filter=AMRCD $COMPARE_REF...HEAD -- "$MIGRATION_PATH/V*.sql" > /tmp/all_changes.txt
# The check for no changes is now handled in the workflow.
# If this script runs, it's because changes were detected.
echo "📝 Migration changes detected:"
# Display the detected changes, indented for readability.
cat /tmp/all_changes.txt | sed 's/^/ /'
echo ""
# Check for deleted files
# Grep for lines starting with 'D' (Deleted). The '|| true' prevents the script from exiting if no matches are found.
DELETED=$(grep "^D" /tmp/all_changes.txt || true)
if [ -n "$DELETED" ]; then
echo "❌ ERROR: Deleted migration files detected!"
echo "$DELETED" | sed 's/^/ /'
echo ""
echo "Flyway migrations should NEVER be deleted after being applied."
echo "If you need to revert changes, create a new migration."
exit 1
fi
# Check for renamed files
# Grep for lines starting with 'R' (Renamed).
RENAMED=$(grep "^R" /tmp/all_changes.txt || true)
if [ -n "$RENAMED" ]; then
echo "❌ ERROR: Renamed migration files detected!"
echo "$RENAMED" | sed 's/^/ /'
echo ""
echo "Flyway migrations should NEVER be renamed after being applied."
echo "This will cause issues with migration history tracking."
echo ""
echo "💡 To fix: Revert the rename and create a new migration file instead."
exit 1
fi
# Check for modified files
# Grep for lines starting with 'M' (Modified).
MODIFIED=$(grep "^M" /tmp/all_changes.txt || true)
if [ -n "$MODIFIED" ]; then
echo "❌ ERROR: Modified migration files detected!"
echo "$MODIFIED" | sed 's/^/ /'
echo ""
echo "Flyway migrations should NEVER be modified after being applied."
echo "This will cause checksum validation failures in environments where it has already been applied."
echo ""
echo "💡 To fix: Revert the changes and create a new migration file instead."
exit 1
fi
# Extract ADDED files for conflict checking in a later step.
# We grep for lines starting with 'A' (Added), then use 'cut' to get just the file path.
# 'touch' ensures the file exists even if there are no added files.
grep "^A" /tmp/all_changes.txt | cut -f2- > /tmp/pr_files.txt || touch /tmp/pr_files.txt
# Set a GitHub Actions output variable to indicate that migration changes were found.
# This is used by the workflow to decide whether to run subsequent steps.
echo "has_changes=true" >> $GITHUB_OUTPUT

View File

@@ -1,96 +0,0 @@
#!/bin/bash
# Exit immediately if a command exits with a non-zero status.
set -e
# Exit if any command in a pipeline fails, not just the last one.
set -o pipefail
# If there are no new versions to check, exit gracefully.
# This file is created by 'validate-versions.sh'.
# This can happen if a PR has changes, but none are new migration files.
if [ ! -s /tmp/versions_pr_unique.txt ]; then
echo " No new migration versions to check for conflicts."
exit 0
fi
# Define the path where Flyway migration files are stored.
MIGRATION_PATH="booklore-api/src/main/resources/db/migration"
echo "🔍 Fetching migration files from $COMPARE_REF..."
# Get ALL existing migration files from the comparison ref (e.g., 'develop' or a tag).
# 'git ls-tree' lists the contents of a tree object.
# The output is piped to grep to filter for only Flyway SQL files.
# '|| touch' ensures the temp file exists even if no files are found.
git ls-tree -r --name-only $COMPARE_REF -- "$MIGRATION_PATH/" 2>/dev/null | \
grep "V.*\.sql$" > /tmp/base_files.txt || touch /tmp/base_files.txt
# Handle the case where no migration files exist in the base branch.
if [ ! -s /tmp/base_files.txt ]; then
echo "⚠️ No migration files found in $COMPARE_REF"
echo "This might be the first migration or the path has changed."
echo ""
echo "✅ Skipping version conflict check."
PR_COUNT=$(wc -l < /tmp/versions_pr_unique.txt)
echo ""
echo "📊 Migration Summary:"
echo " - Existing migrations in $COMPARE_REF: 0"
echo " - New migrations in this PR: $PR_COUNT"
exit 0
fi
echo "📋 Found $(wc -l < /tmp/base_files.txt) migration files in $COMPARE_REF"
# Extract versions from the base files.
# The loop reads each file path, extracts the version number from the filename,
# and appends it to a temporary file.
> /tmp/versions_base.txt
while IFS= read -r file; do
filename=$(basename "$file")
# sed extracts the version number (e.g., 1.0.0) from a filename like 'V1.0.0__description.sql'.
version=$(echo "$filename" | sed -n 's/^V\([0-9.]*\)__.*/\1/p')
[ -n "$version" ] && echo "$version" >> /tmp/versions_base.txt
done < /tmp/base_files.txt
# Create a file with only unique, sorted version numbers from the base.
sort -u /tmp/versions_base.txt > /tmp/versions_base_unique.txt
BASE_COUNT=$(wc -l < /tmp/versions_base_unique.txt)
echo "📊 Found $BASE_COUNT unique versions in $COMPARE_REF"
# Find conflicts between base versions and versions from NEW PR files.
# 'comm -12' finds lines common to both sorted files.
CONFLICTS=$(comm -12 /tmp/versions_base_unique.txt /tmp/versions_pr_unique.txt)
# If conflicts are found, report them and exit with an error.
if [ -n "$CONFLICTS" ]; then
echo "❌ Version conflicts detected!"
echo ""
echo "The following versions from your new migration files already exist in $COMPARE_REF:"
echo "$CONFLICTS" | sed 's/^/ V/'
echo ""
# Show which files have conflicting versions for easier debugging.
echo "Conflicting files:"
while IFS= read -r version; do
echo " Version V$version exists in:"
grep "V${version}__" /tmp/base_files.txt | xargs -n1 basename | sed 's/^/ BASE: /'
# /tmp/pr_files.txt contains only added files from the PR (from analyze-changes.sh).
grep "V${version}__" /tmp/pr_files.txt | xargs -n1 basename | sed 's/^/ PR: /'
done <<< "$CONFLICTS"
echo ""
echo "💡 To fix: Use a version number that doesn't exist in $COMPARE_REF"
exit 1
fi
echo "✅ No version conflicts detected."
# Get the count of new migrations in the PR.
PR_COUNT=$(wc -l < /tmp/versions_pr_unique.txt)
# Print a final summary.
echo ""
echo "📊 Migration Summary:"
echo " - Existing migrations in $COMPARE_REF: $BASE_COUNT"
echo " - New migrations in this PR: $PR_COUNT"

View File

@@ -1,41 +0,0 @@
#!/bin/bash
# Exit immediately if a command exits with a non-zero status.
set -e
# Exit if any command in a pipeline fails, not just the last one.
set -o pipefail
# The target branch of the pull request (e.g., 'develop', 'master') is passed as the first argument.
TARGET_BRANCH="$1"
echo "🎯 Target branch: $TARGET_BRANCH"
# Handle cases where the target branch is not specified, such as a direct push to a branch.
if [ -z "$TARGET_BRANCH" ]; then
echo "⚠️ No target branch specified (e.g., a direct push event). Defaulting to compare with 'develop'."
TARGET_BRANCH="develop"
fi
# Logic to determine the comparison reference based on the target branch.
if [ "$TARGET_BRANCH" = "master" ]; then
# For PRs to 'master', we compare against the latest git tag.
# This is common for release workflows where 'master' only contains tagged releases.
if ! LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null); then
echo "⚠️ No tags found in repository. Skipping conflict check."
# Set output to signal the workflow to stop.
echo "has_ref=false" >> $GITHUB_OUTPUT
exit 0
fi
echo "📌 Comparing against last tag: $LAST_TAG"
# Set the COMPARE_REF environment variable for subsequent steps in the job.
echo "COMPARE_REF=$LAST_TAG" >> $GITHUB_ENV
else
# For all other cases (PRs to 'develop', other feature branches, or direct pushes),
# we compare against the 'develop' branch.
echo "🔄 Comparing against head of develop branch"
# Ensure the local 'develop' branch is up-to-date with the remote.
git fetch origin develop:develop
# Set the COMPARE_REF to the remote develop branch.
echo "COMPARE_REF=origin/develop" >> $GITHUB_ENV
fi
# Set a GitHub Actions output variable to indicate that a valid comparison ref was found.
echo "has_ref=true" >> $GITHUB_OUTPUT

View File

@@ -1,79 +0,0 @@
#!/bin/bash
# Exit immediately if a command exits with a non-zero status.
set -e
# Exit if any command in a pipeline fails, not just the last one.
set -o pipefail
# Define the path where Flyway migration files are stored.
MIGRATION_PATH="booklore-api/src/main/resources/db/migration"
# --- Part 1: Check for duplicate versions within the PR branch itself ---
# Get ALL migration files in the current HEAD of the PR branch for an internal duplicate check.
find "$MIGRATION_PATH" -type f -name "V*.sql" > /tmp/all_pr_files.txt
# Check for duplicate versions within the PR branch. This prevents merging a branch
# that contains multiple files with the same version number.
echo "🔎 Checking for duplicate versions in the branch..."
> /tmp/versions_all_pr.txt
# Loop through all found migration files and extract their version numbers.
while IFS= read -r file; do
filename=$(basename "$file")
# sed extracts the version number (e.g., 1.0.0) from a filename like 'V1.0.0__description.sql'.
version=$(echo "$filename" | sed -n 's/^V\([0-9.]*\)__.*/\1/p')
[ -n "$version" ] && echo "$version" >> /tmp/versions_all_pr.txt
done < /tmp/all_pr_files.txt
# 'uniq -d' filters for lines that appear more than once in the sorted list.
sort /tmp/versions_all_pr.txt | uniq -d > /tmp/duplicates_in_pr.txt
# If the duplicates file is not empty, report the error and exit.
if [ -s /tmp/duplicates_in_pr.txt ]; then
echo "❌ Duplicate migration versions found within the branch!"
echo ""
echo "The following versions are duplicated:"
while IFS= read -r version; do
echo " - Version V$version is used by:"
# Show the conflicting files for easy debugging.
grep "V${version}__" /tmp/all_pr_files.txt | xargs -n1 basename | sed 's/^/ /'
done < /tmp/duplicates_in_pr.txt
echo ""
echo "💡 To fix: Ensure all migration files have a unique version number."
exit 1
fi
echo "✅ No duplicate versions found within the branch."
# --- Part 2: Extract versions from NEWLY ADDED files for conflict checking against the base branch ---
# /tmp/pr_files.txt is created by analyze-changes.sh and contains only ADDED files.
# If the file doesn't exist or is empty, there's nothing to check.
if [ ! -f /tmp/pr_files.txt ] || [ ! -s /tmp/pr_files.txt ]; then
echo " No new migration files to check for conflicts."
# Set output to signal the workflow to skip the conflict check step.
echo "has_versions=false" >> $GITHUB_OUTPUT
exit 0
fi
echo "🔎 Extracting versions from new files..."
> /tmp/versions_pr.txt
# Loop through only the NEWLY ADDED files and extract their versions.
while IFS= read -r file; do
filename=$(basename "$file")
version=$(echo "$filename" | sed -n 's/^V\([0-9.]*\)__.*/\1/p')
[ -n "$version" ] && echo "$version" >> /tmp/versions_pr.txt
done < /tmp/pr_files.txt
# If no valid versions were extracted from the new files, exit.
if [ ! -s /tmp/versions_pr.txt ]; then
echo " No versions found in new migration files."
echo "has_versions=false" >> $GITHUB_OUTPUT
exit 0
fi
# Create a sorted, unique list of versions from the new files.
# This file will be used by 'check-conflicts.sh'.
sort -u /tmp/versions_pr.txt > /tmp/versions_pr_unique.txt
# Set output to signal that there are new versions to check for conflicts.
echo "has_versions=true" >> $GITHUB_OUTPUT

View File

@@ -9,30 +9,28 @@ on:
branches:
- '**'
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
check-for-migrations:
name: Check for DB Migrations
if: github.event_name == 'pull_request' && (github.base_ref == 'master' || github.base_ref == 'develop')
runs-on: ubuntu-latest
outputs:
has_migrations: ${{ steps.check_migrations.outputs.has_migrations }}
has_migrations: ${{ steps.filter.outputs.migrations }}
steps:
- name: Checkout Repository for Diff
- name: Checkout Repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Detect Flyway Migration Changes
id: check_migrations
run: |
# Compare PR head with the target base branch
if git diff --name-only origin/${{ github.base_ref }}...HEAD | grep -q "booklore-api/src/main/resources/db/migration/V.*.sql"; then
echo "Migration file changes detected. Proceeding with migration preview."
echo "has_migrations=true" >> $GITHUB_OUTPUT
else
echo "No migration file changes detected. Skipping migration preview."
echo "has_migrations=false" >> $GITHUB_OUTPUT
fi
- name: Detect Migration Changes
uses: dorny/paths-filter@v3
id: filter
with:
filters: |
migrations:
- 'booklore-api/src/main/resources/db/migration/V*.sql'
flyway-migration-preview:
name: Flyway DB Migration Preview
@@ -90,7 +88,7 @@ jobs:
test-pr:
name: Run Tests on Pull Request
needs: [check-for-migrations, flyway-migration-preview]
if: always() && github.event_name == 'pull_request' && (needs.flyway-migration-preview.result == 'success' || needs.flyway-migration-preview.result == 'skipped')
if: github.event_name == 'pull_request' && (needs.flyway-migration-preview.result == 'success' || needs.flyway-migration-preview.result == 'skipped')
runs-on: ubuntu-latest
permissions:
@@ -102,7 +100,18 @@ jobs:
- name: Checkout Repository
uses: actions/checkout@v6
- name: Detect Changed Paths
uses: dorny/paths-filter@v3
id: filter
with:
filters: |
backend_or_docker:
- 'booklore-api/**'
- 'Dockerfile'
- 'start.sh'
- name: Set Up JDK 21
if: steps.filter.outputs.backend_or_docker == 'true'
uses: actions/setup-java@v5
with:
java-version: '21'
@@ -110,6 +119,7 @@ jobs:
cache: 'gradle'
- name: Execute Backend Tests
if: steps.filter.outputs.backend_or_docker == 'true'
id: backend_tests
working-directory: ./booklore-api
run: |
@@ -118,8 +128,8 @@ jobs:
continue-on-error: true
- name: Publish Backend Test Results
if: always() && steps.backend_tests.conclusion != 'skipped'
uses: EnricoMi/publish-unit-test-result-action@v2
if: always()
with:
files: booklore-api/build/test-results/**/*.xml
check_name: Backend Test Results
@@ -128,8 +138,8 @@ jobs:
report_suite_logs: 'any'
- name: Upload Backend Test Reports
if: always() && steps.backend_tests.conclusion != 'skipped'
uses: actions/upload-artifact@v6
if: always()
with:
name: test-reports-pr-${{ github.event.pull_request.number }}
path: |
@@ -143,6 +153,11 @@ jobs:
echo "❌ Backend tests failed! Check the test results above."
exit 1
- name: Skip Backend Tests
if: steps.filter.outputs.backend_or_docker == 'false'
run: |
echo "✅ No backend changes detected. Skipping backend tests."
- name: PR Validation Complete
run: |
echo "✅ All PR validation checks passed!"
@@ -163,7 +178,23 @@ jobs:
with:
fetch-depth: 0
- name: Detect Changed Paths
uses: dorny/paths-filter@v3
id: filter
with:
filters: |
backend_or_docker:
- 'booklore-api/**'
- 'Dockerfile'
- 'start.sh'
- name: Skip Build and Push
if: steps.filter.outputs.backend_or_docker == 'false'
run: |
echo "✅ No backend/Docker changes detected. Skipping image build and publish."
- name: Set Up JDK 21
if: steps.filter.outputs.backend_or_docker == 'true'
uses: actions/setup-java@v5
with:
java-version: '21'
@@ -171,18 +202,21 @@ jobs:
cache: 'gradle'
- name: Execute Backend Tests
if: steps.filter.outputs.backend_or_docker == 'true'
working-directory: ./booklore-api
run: |
echo "Running backend tests before building image..."
./gradlew test --no-daemon --parallel --build-cache
- name: Authenticate to Docker Hub
- name: Authenticate to Docker Registries
if: steps.filter.outputs.backend_or_docker == 'true'
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Authenticate to GitHub Container Registry
if: steps.filter.outputs.backend_or_docker == 'true'
uses: docker/login-action@v3
with:
registry: ghcr.io
@@ -190,12 +224,15 @@ jobs:
password: ${{ github.token }}
- name: Set Up QEMU for Multi-Architecture Builds
if: steps.filter.outputs.backend_or_docker == 'true'
uses: docker/setup-qemu-action@v3
- name: Set Up Docker Buildx
if: steps.filter.outputs.backend_or_docker == 'true'
uses: docker/setup-buildx-action@v3
- name: Retrieve Latest Master Version Tag
if: steps.filter.outputs.backend_or_docker == 'true'
id: get_version
run: |
latest_tag=$(git tag --list "v*" --sort=-v:refname | head -n 1)
@@ -204,7 +241,7 @@ jobs:
echo "Latest master tag: $latest_tag"
- name: Determine Version Bump (Master Only)
if: github.ref == 'refs/heads/master'
if: steps.filter.outputs.backend_or_docker == 'true' && github.ref == 'refs/heads/master'
id: determine_bump
env:
GH_TOKEN: ${{ github.token }}
@@ -260,6 +297,7 @@ jobs:
echo "new_tag=$next_version" >> $GITHUB_ENV
- name: Generate Image Tag
if: steps.filter.outputs.backend_or_docker == 'true'
id: set_image_tag
run: |
branch="${GITHUB_REF#refs/heads/}"
@@ -275,7 +313,8 @@ jobs:
echo "image_tag=$image_tag" >> $GITHUB_ENV
echo "Image tag: $image_tag"
- name: Build and push Docker image
- name: Build and Push Docker Images
if: steps.filter.outputs.backend_or_docker == 'true'
uses: docker/build-push-action@v6
with:
context: .
@@ -295,7 +334,7 @@ jobs:
type=registry,ref=ghcr.io/booklore-app/booklore:buildcache,mode=max
- name: Push Latest Tag (Master Only)
if: github.ref == 'refs/heads/master'
if: steps.filter.outputs.backend_or_docker == 'true' && github.ref == 'refs/heads/master'
uses: docker/build-push-action@v6
with:
context: .
@@ -312,7 +351,7 @@ jobs:
cache-from: type=gha
- name: Update GitHub Release Draft (Master Only)
if: github.ref == 'refs/heads/master'
if: steps.filter.outputs.backend_or_docker == 'true' && github.ref == 'refs/heads/master'
uses: release-drafter/release-drafter@v6
with:
tag: ${{ env.new_tag }}
@@ -321,7 +360,7 @@ jobs:
GITHUB_TOKEN: ${{ github.token }}
- name: Publish GitHub Draft Release (Master Only)
if: github.ref == 'refs/heads/master'
if: steps.filter.outputs.backend_or_docker == 'true' && github.ref == 'refs/heads/master'
env:
GITHUB_TOKEN: ${{ github.token }}
run: |