diff --git a/.gitea/workflows/ci-cd.yaml b/.gitea/workflows/ci-cd.yaml index 8686d57..d3572de 100644 --- a/.gitea/workflows/ci-cd.yaml +++ b/.gitea/workflows/ci-cd.yaml @@ -27,6 +27,12 @@ on: branches: - main types: [opened, synchronize, reopened, labeled] + # Only run PR CI if the commit doesn't already have passing branch CI + if: | + github.event_name == 'pull_request' && + (github.event.action == 'opened' || + github.event.action == 'synchronize' || + github.event.action == 'reopened') paths-ignore: - 'README.md' - 'doc/**' @@ -51,35 +57,190 @@ env: CI_REGISTRY: "gitea.arcodange.lab" jobs: - ci-pipeline: - name: CI Pipeline - runs-on: ubuntu-latest - + build-cache: + name: Build Docker Cache + runs-on: ubuntu-latest-ca + if: "!contains(github.event.head_commit.message, '[skip ci]') && github.actor != 'ci-bot'" + outputs: + deps_hash: ${{ steps.calculate_hash.outputs.deps_hash }} + cache_hit: ${{ steps.check_cache.outputs.cache_hit }} steps: - name: Checkout code uses: actions/checkout@v4 - - name: Set up Go - uses: actions/setup-go@v4 + - name: Calculate dependency hash + id: calculate_hash + run: | + # Calculate hash of go.mod + go.sum + Dockerfile.build (inline, no script needed) + DEPS_HASH=$(sha256sum go.mod go.sum docker/Dockerfile.build | sha256sum | cut -d' ' -f1 | head -c 12) + echo "Dependency hash: $DEPS_HASH" + echo "deps_hash=$DEPS_HASH" >> $GITHUB_OUTPUT + + - name: Check for existing cache (optimized with fallback) + id: check_cache + run: | + # Check if image exists in registry using optimized approach with fallback + IMAGE_NAME="${{ env.CI_REGISTRY }}/${{ env.GITEA_ORG }}/${{ env.GITEA_REPO }}-build-cache:${{ steps.calculate_hash.outputs.deps_hash }}" + + # Fast check using docker manifest inspect (lighter than pull) + echo "🔍 Checking cache: $IMAGE_NAME" + + # Try manifest inspect first (fastest method, but experimental) + if docker manifest inspect "$IMAGE_NAME" >/dev/null 2>&1; then + echo "✅ Cache hit - using existing build cache (manifest inspect)" + echo "cache_hit=true" >> $GITHUB_OUTPUT + else + # Fallback to docker pull if manifest inspect fails (more reliable) + echo "âš ī¸ Manifest inspect failed, falling back to docker pull..." + if docker pull "$IMAGE_NAME" >/dev/null 2>&1; then + echo "✅ Cache hit - using existing build cache (fallback: docker pull)" + echo "cache_hit=true" >> $GITHUB_OUTPUT + else + echo "âš ī¸ Cache miss - will build new cache image" + echo "cache_hit=false" >> $GITHUB_OUTPUT + fi + fi + + - name: Login to Gitea Container Registry + if: steps.check_cache.outputs.cache_hit == 'false' + uses: docker/login-action@v3 with: - go-version: '1.26.1' - cache: true + registry: ${{ env.CI_REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.PACKAGES_TOKEN }} - - name: Install dependencies - run: go mod tidy - # SINGLE swag installation - reused for all steps - - name: Install swag (once) - run: go install github.com/swaggo/swag/cmd/swag@latest + + - name: Build and push Docker cache image + if: steps.check_cache.outputs.cache_hit == 'false' + run: | + IMAGE_NAME="${{ env.CI_REGISTRY }}/${{ env.GITEA_ORG }}/${{ env.GITEA_REPO }}-build-cache:${{ steps.calculate_hash.outputs.deps_hash }}" + echo "Building cache image: $IMAGE_NAME" + + # Build the image using traditional docker build + docker build \ + --file docker/Dockerfile.build \ + --tag "$IMAGE_NAME" \ + . + + # Push the image + docker push "$IMAGE_NAME" + + echo "✅ Build cache image pushed successfully" + + ci-pipeline: + name: CI Pipeline + needs: build-cache + runs-on: ubuntu-latest-ca + if: "!contains(github.event.head_commit.message, '[skip ci]') && github.actor != 'ci-bot'" + + container: + image: ${{ env.CI_REGISTRY }}/${{ env.GITEA_ORG }}/${{ env.GITEA_REPO }}-build-cache:${{ needs.build-cache.outputs.deps_hash }} + + services: + postgres: + image: postgres:15 + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: dance_lessons_coach_bdd_test + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set database environment variables + run: | + echo "DLC_DATABASE_HOST=postgres" >> $GITHUB_ENV + echo "DLC_DATABASE_PORT=5432" >> $GITHUB_ENV + echo "DLC_DATABASE_USER=postgres" >> $GITHUB_ENV + echo "DLC_DATABASE_PASSWORD=postgres" >> $GITHUB_ENV + echo "DLC_DATABASE_NAME=dance_lessons_coach_bdd_test" >> $GITHUB_ENV + echo "DLC_DATABASE_SSL_MODE=disable" >> $GITHUB_ENV + + - name: Restore Swagger Docs Cache + id: cache-swagger-restore + uses: actions/cache/restore@v5 + with: + path: | + pkg/server/docs/docs.go + pkg/server/docs/swagger.json + pkg/server/docs/swagger.yaml + key: swagger-docs-${{ hashFiles('cmd/server/main.go', 'pkg/greet/*.go', 'pkg/server/*.go', 'go.mod') }} + restore-keys: | + swagger-docs- - name: Generate Swagger Docs - run: cd pkg/server && go generate + if: steps.cache-swagger-restore.outputs.cache-hit != 'true' + run: go generate ./pkg/server + + - name: Save Swagger Docs Cache + if: steps.cache-swagger-restore.outputs.cache-hit != 'true' + id: cache-swagger-save + uses: actions/cache/save@v5 + with: + path: | + pkg/server/docs/docs.go + pkg/server/docs/swagger.json + pkg/server/docs/swagger.yaml + key: ${{ steps.cache-swagger-restore.outputs.cache-primary-key }} - name: Build all packages run: go build ./... + - - name: Run tests with coverage - run: go test ./... -cover -v + - name: Wait for PostgreSQL to be ready + run: | + echo "Waiting for PostgreSQL to be ready..." + for i in {1..30}; do + if pg_isready -h postgres -p 5432 -U postgres -d dance_lessons_coach_bdd_test; then + echo "✅ PostgreSQL is ready!" + break + fi + echo "Waiting for PostgreSQL... ($i/30)" + sleep 2 + done + + # Verify PostgreSQL is accessible + if ! pg_isready -h postgres -p 5432 -U postgres -d dance_lessons_coach_bdd_test; then + echo "❌ PostgreSQL failed to start" + exit 1 + fi + + - name: Run BDD tests with strict validation and coverage + run: | + echo "Running BDD tests with strict validation and coverage..." + # Use the run-bdd-tests.sh script which fails on undefined/pending steps + # In CI environment, PostgreSQL is already running as a service + export DLC_DATABASE_HOST=postgres + export DLC_DATABASE_PORT=5432 + export DLC_DATABASE_USER=postgres + export DLC_DATABASE_PASSWORD=postgres + export DLC_DATABASE_NAME=dance_lessons_coach_bdd_test + export DLC_DATABASE_SSL_MODE=disable + ./scripts/run-bdd-tests.sh + + # Generate BDD coverage report + go tool cover -func=coverage.out > bdd_coverage.txt + + # Extract BDD coverage percentage and set as environment variable + BDD_COVERAGE=$(grep "total:" bdd_coverage.txt | grep -oP '\d+\.\d+' | head -1) + echo "BDD Coverage: ${BDD_COVERAGE}%" + echo "DLC_BDD_COVERAGE=${BDD_COVERAGE}%" >> $GITHUB_ENV + + - name: Run unit tests with coverage + run: | + echo "Running unit tests with PostgreSQL service..." + # Run unit tests excluding BDD tests (already run above) + go test ./pkg/... ./cmd/... -coverprofile=unit_coverage.out -v + + # Generate unit coverage report + go tool cover -func=unit_coverage.out > unit_coverage.txt + + # Extract unit test coverage percentage and set as environment variable + UNIT_COVERAGE=$(grep "total:" unit_coverage.txt | grep -oP '\d+\.\d+' | head -1) + echo "Unit Coverage: ${UNIT_COVERAGE}%" + echo "DLC_UNIT_COVERAGE=${UNIT_COVERAGE}%" >> $GITHUB_ENV - name: Run go fmt run: go fmt ./... @@ -99,45 +260,51 @@ jobs: # path: pkg/server/docs/swagger.json # retention-days: 1 - # Version management and Docker build (main branch only) - - name: Version management and Docker build - if: github.ref == 'refs/heads/main' + # Badge and version updates - multiple commits, single push + # All documentation updates happen in one step with single push at the end + - name: Update badges and version (multiple commits, single push) + if: always() && github.actor != 'ci-bot' run: | - # Analyze last commit message - LAST_COMMIT=$(git log -1 --pretty=%B | head -1) - VERSION_BUMPED="false" + echo "đŸŽ¯ Updating badges and version..." + echo "BDD Coverage: ${DLC_BDD_COVERAGE:-Not set}" + echo "Unit Coverage: ${DLC_UNIT_COVERAGE:-Not set}" - # Automatic version bump based on commit type - if echo "$LAST_COMMIT" | grep -q "^✨ feat:"; then - echo "đŸŽ¯ Feature commit detected - bumping MINOR version" - ./scripts/version-bump.sh minor - VERSION_BUMPED="true" - elif echo "$LAST_COMMIT" | grep -q "^🐛 fix:"; then - echo "🐛 Fix commit detected - bumping PATCH version" - ./scripts/version-bump.sh patch - VERSION_BUMPED="true" - elif echo "$LAST_COMMIT" | grep -q "BREAKING CHANGE"; then - echo "đŸ’Ĩ Breaking change detected - bumping MAJOR version" - ./scripts/version-bump.sh major - VERSION_BUMPED="true" - else - echo "â­ī¸ No automatic version bump needed" + # Configure git + git config user.name "CI Bot" + git config user.email "ci@arcodange.fr" + + # Extract coverage values (remove % sign) + BDD_COV=${DLC_BDD_COVERAGE%"%"} + UNIT_COV=${DLC_UNIT_COVERAGE%"%"} + + # Update BDD coverage badge if value is set (use --no-push to avoid race conditions) + if [ -n "$BDD_COV" ]; then + echo "📊 Updating BDD coverage badge to ${BDD_COV}%" + ./scripts/ci-update-coverage-badge.sh "$BDD_COV" "bdd" --no-push fi - # Update swagger version regardless of bump - source VERSION - NEW_VERSION="$MAJOR.$MINOR.$PATCH${PRERELEASE:+-$PRERELEASE}" - sed -i "s|// @version [0-9.]*|// @version $NEW_VERSION|" cmd/server/main.go + # Update Unit coverage badge if value is set (use --no-push to avoid race conditions) + if [ -n "$UNIT_COV" ]; then + echo "📊 Updating Unit coverage badge to ${UNIT_COV}%" + ./scripts/ci-update-coverage-badge.sh "$UNIT_COV" "unit" --no-push + fi - # Commit version changes if bumped - if [ "$VERSION_BUMPED" = "true" ]; then - git config --global user.name "CI Bot" - git config --global user.email "ci@arcodange.fr" - git add VERSION cmd/server/main.go README.md - git commit -m "chore: auto version bump [skip ci]" || echo "No changes to commit" + # Check for version bump on main branch + if [ "${{ github.ref }}" = "refs/heads/main" ]; then + echo "🔖 Checking for version bump..." + ./scripts/ci-version-bump.sh "${{ github.event.head_commit.message }}" --no-push + fi + + # Single push for all commits (this is the ONLY push in the entire workflow) + if [ -n "$(git status --porcelain)" ]; then + echo "💾 Changes detected, pushing all commits..." git push + echo "🎉 Successfully pushed all updates" + else + echo "â„šī¸ No changes to push" fi + # Docker build and push (main branch only) - name: Login to Gitea Container Registry if: github.ref == 'refs/heads/main' uses: docker/login-action@v3 @@ -146,19 +313,24 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.PACKAGES_TOKEN }} - - name: Set up Docker Buildx - if: github.ref == 'refs/heads/main' - uses: docker/setup-buildx-action@v3 - - name: Build and push Docker image if: github.ref == 'refs/heads/main' run: | source VERSION IMAGE_VERSION="$MAJOR.$MINOR.$PATCH${PRERELEASE:+-$PRERELEASE}" + # Use the template file with proper dependency hash replacement + DEPS_HASH="${{ needs.build-cache.outputs.deps_hash }}" + echo "Using dependency hash: $DEPS_HASH" + + # Create Dockerfile.prod from template + sed "s/{{DEPS_HASH}}/$DEPS_HASH/g" docker/Dockerfile.prod.template > docker/Dockerfile.prod + TAGS="$IMAGE_VERSION latest ${{ github.sha }}" echo "Building Docker image with tags: $TAGS" - docker build -t dance-lessons-coach . + + # Build the production image + docker build -t dance-lessons-coach -f docker/Dockerfile.prod . for TAG in $TAGS; do IMAGE_NAME="${{ env.CI_REGISTRY }}/${{ env.GITEA_ORG }}/${{ env.GITEA_REPO }}:$TAG" @@ -175,4 +347,4 @@ jobs: echo "đŸ“Ļ Published Docker images:" echo " - ${{ env.CI_REGISTRY }}/${{ env.GITEA_ORG }}/${{ env.GITEA_REPO }}:$IMAGE_VERSION" echo " - ${{ env.CI_REGISTRY }}/${{ env.GITEA_ORG }}/${{ env.GITEA_REPO }}:latest" - echo " - ${{ env.CI_REGISTRY }}/${{ env.GITEA_ORG }}/${{ env.GITEA_REPO }}:${{ github.sha }}" \ No newline at end of file + echo " - ${{ env.CI_REGISTRY }}/${{ env.GITEA_ORG }}/${{ env.GITEA_REPO }}:${{ github.sha }}" diff --git a/scripts/ci-update-coverage-badge.sh b/scripts/ci-update-coverage-badge.sh new file mode 100755 index 0000000..7be7477 --- /dev/null +++ b/scripts/ci-update-coverage-badge.sh @@ -0,0 +1,172 @@ +#!/bin/bash +# CI script to update coverage badge in README.md +# Usage: scripts/ci-update-coverage-badge.sh [badge_type] [flags] +# badge_type can be "bdd", "unit", or empty for combined coverage +# flags: --no-commit (skip git commit), --no-push (skip git push) + +set -e + +if [ -z "$1" ]; then + echo "Error: Coverage percentage not provided" + exit 1 +fi + +COVERAGE=$1 +BADGE_TYPE=${2:-"combined"} + +# Parse flags +NO_COMMIT=false +NO_PUSH=false + +for arg in "$@"; do + if [ "$arg" = "--no-commit" ]; then + NO_COMMIT=true + elif [ "$arg" = "--no-push" ]; then + NO_PUSH=true + fi +done + +# Determine badge color +if (( $(echo "$COVERAGE >= 80" | bc -l) )); then + COLOR="brightgreen" +elif (( $(echo "$COVERAGE >= 50" | bc -l) )); then + COLOR="yellow" +else + COLOR="red" +fi + +# Create different badge URLs and markdown format based on type +if [ "$BADGE_TYPE" = "bdd" ]; then + BADGE_URL="https://img.shields.io/badge/BDD_Coverage-${COVERAGE}%-${COLOR}?style=flat-square" + BADGE_MARKDOWN="[![BDD Coverage](${BADGE_URL})](https://gitea.arcodange.lab/arcodange/dance-lessons-coach)" + SEARCH_PATTERN="BDD_Coverage-.*-.*?style=flat-square" +elif [ "$BADGE_TYPE" = "unit" ]; then + BADGE_URL="https://img.shields.io/badge/Unit_Coverage-${COVERAGE}%-${COLOR}?style=flat-square" + BADGE_MARKDOWN="[![Unit Coverage](${BADGE_URL})](https://gitea.arcodange.lab/arcodange/dance-lessons-coach)" + SEARCH_PATTERN="Unit_Coverage-.*-.*?style=flat-square" +else + BADGE_URL="https://img.shields.io/badge/coverage-${COVERAGE}%-${COLOR}?style=flat-square" + BADGE_MARKDOWN="[![Coverage](${BADGE_URL})](https://gitea.arcodange.lab/arcodange/dance-lessons-coach)" + SEARCH_PATTERN="coverage-.*-.*?style=flat-square" +fi + +# Clean up any malformed badge lines from previous runs +# Remove lines starting with "nhttps://" or "https://" that aren't proper markdown +sed -i.bak '/^nhttps:\/\/.*img.shields.io.*Coverage/d' README.md 2>/dev/null || true +sed -i.bak '/^https:\/\/.*img.shields.io.*Coverage/d' README.md 2>/dev/null || true + +# Remove old duplicate badges for the specific type being updated +if [ "$BADGE_TYPE" = "bdd" ] || [ "$BADGE_TYPE" = "unit" ]; then + # Remove all existing badges of this type before adding new one + sed -i.bak "/${BADGE_TYPE}_Coverage/d" README.md 2>/dev/null || true +fi + +rm -f README.md.bak + +# Only update if coverage has actually changed +if grep -q "${BADGE_TYPE}_Coverage-${COVERAGE}%" README.md || grep -q "coverage-${COVERAGE}%" README.md; then + echo "Coverage badge already up to date at ${COVERAGE}%" + exit 0 +fi + +# Also check if badge already exists with this coverage (more flexible pattern) +if [ "$BADGE_TYPE" = "bdd" ] || [ "$BADGE_TYPE" = "unit" ]; then + # Capitalize first letter for badge name + if [ "$BADGE_TYPE" = "unit" ]; then + BADGE_NAME="Unit" + else + BADGE_NAME="BDD" + fi + if grep -q "\[!\[${BADGE_NAME} Coverage\].*${COVERAGE}%" README.md; then + echo "Coverage badge already exists at ${COVERAGE}%" + exit 0 + fi +fi + +# Cross-platform sed command +# Detect if we're on macOS (BSD sed) or Linux (GNU sed) +SED_CMD="" +if [[ "$(uname)" == "Darwin" ]]; then + # macOS - requires empty string after -i + SED_CMD="sed -i ''" +else + # Linux - standard GNU sed + SED_CMD="sed -i" +fi + +# Update README - handle both old and new badge formats +if [ "$BADGE_TYPE" = "bdd" ] || [ "$BADGE_TYPE" = "unit" ]; then + # For BDD/Unit badges, add them if they don't exist, or update if they do + if grep -q "${BADGE_TYPE}_Coverage" README.md; then + # Update existing badge with proper markdown format + $SED_CMD "s|^\[!\[${BADGE_TYPE} Coverage\].*|"${BADGE_MARKDOWN}"|" README.md + else + # Add new badge line after the License badge (more reliable reference) + # Use a more reliable approach with temporary file for cross-platform compatibility + TEMP_FILE=$(mktemp) + awk -v new_badge="${BADGE_MARKDOWN}" '{ + if ($0 ~ /\[!\[License\].*license-MIT-green/) { + print $0 + print new_badge + } else { + print $0 + } + }' README.md > "$TEMP_FILE" + mv "$TEMP_FILE" README.md + fi +else + # For combined coverage, use the original logic + $SED_CMD "s|^\[!\[Coverage\].*|"${BADGE_MARKDOWN}"|" README.md +fi + +# Set up git +git config --global user.name "CI Bot" +git config --global user.email "ci@arcodange.fr" + +# Set up credentials using Gitea token +if [ -n "$PACKAGES_TOKEN" ]; then + git config --global credential.helper store + echo "https://${PACKAGES_TOKEN}@gitea.arcodange.lab" > ~/.git-credentials +fi + +git add README.md + +# Skip commit if --no-commit flag is set +if [ "$NO_COMMIT" = true ]; then + echo "Skipping git commit due to --no-commit flag" + echo "Coverage badge updated to ${COVERAGE}% in README.md (not committed)" + exit 0 +fi + +if git commit -m "🤖 chore: update coverage badge to ${COVERAGE}% [skip ci]"; then + # Skip push if --no-push flag is set + if [ "$NO_PUSH" = true ]; then + echo "Skipping git push due to --no-push flag" + echo "Coverage badge updated to ${COVERAGE}% and committed locally" + exit 0 + fi + + # Try push with retry logic for race conditions + for i in 1 2 3; do + if git push; then + echo "Successfully updated coverage badge to ${COVERAGE}%" + # Update local repo to the new HEAD after successful push + git fetch origin + git reset --hard origin/${GITHUB_REF_NAME:-${CI_COMMIT_REF_NAME:-main}} + exit 0 + else + echo "Push attempt $i failed, retrying..." + if [ $i -eq 3 ]; then + echo "Final push attempt failed - another job may have updated the badge" + git pull --rebase || true + git push || echo "Recovery push also failed" + # Ensure we're on the latest commit even if push failed + git fetch origin + git reset --hard origin/${GITHUB_REF_NAME:-${CI_COMMIT_REF_NAME:-main}} + fi + sleep 2 + fi + done +else + echo "No coverage change to commit" +fi diff --git a/scripts/ci-version-bump.sh b/scripts/ci-version-bump.sh new file mode 100755 index 0000000..df3960b --- /dev/null +++ b/scripts/ci-version-bump.sh @@ -0,0 +1,95 @@ +#!/bin/bash +# CI script to handle automatic version bumping +# Usage: scripts/ci-version-bump.sh [--no-push] + +set -e + +if [ -z "$1" ]; then + echo "Error: Commit message not provided" + exit 1 +fi + +LAST_COMMIT=$1 +VERSION_BUMPED="false" +NO_PUSH=false + +# Parse flags +for arg in "$@"; do + if [ "$arg" = "--no-push" ]; then + NO_PUSH=true + fi +done + +# Automatic version bump based on commit type +if echo "$LAST_COMMIT" | grep -q "^✨ feat:"; then + echo "đŸŽ¯ Feature commit detected - bumping MINOR version" + ./scripts/version-bump.sh minor + VERSION_BUMPED="true" +elif echo "$LAST_COMMIT" | grep -q "^🐛 fix:"; then + echo "🐛 Fix commit detected - bumping PATCH version" + ./scripts/version-bump.sh patch + VERSION_BUMPED="true" +elif echo "$LAST_COMMIT" | grep -q "BREAKING CHANGE"; then + echo "đŸ’Ĩ Breaking change detected - bumping MAJOR version" + ./scripts/version-bump.sh major + VERSION_BUMPED="true" +else + echo "â­ī¸ No automatic version bump needed" +fi + +# Update swagger version regardless of bump +source VERSION +NEW_VERSION="$MAJOR.$MINOR.$PATCH${PRERELEASE:+-$PRERELEASE}" + +# Cross-platform sed command +# Detect if we're on macOS (BSD sed) or Linux (GNU sed) +SED_CMD="" +if [[ "$(uname)" == "Darwin" ]]; then + # macOS - requires empty string after -i + SED_CMD="sed -i ''" +else + # Linux - standard GNU sed + SED_CMD="sed -i" +fi + +$SED_CMD "s|// @version [0-9.]*|// @version $NEW_VERSION|" cmd/server/main.go + +# Commit version changes if bumped +if [ "$VERSION_BUMPED" = "true" ]; then + git config --global user.name "CI Bot" + git config --global user.email "ci@arcodange.fr" + + # Set up credentials using Gitea token + if [ -n "$PACKAGES_TOKEN" ]; then + git config --global credential.helper store + echo "https://${PACKAGES_TOKEN}@gitea.arcodange.lab" > ~/.git-credentials + fi + + git add VERSION cmd/server/main.go README.md + if git commit -m "chore: auto version bump [skip ci]"; then + # Skip push if --no-push flag is set + if [ "$NO_PUSH" = true ]; then + echo "Skipping git push due to --no-push flag" + echo "Successfully bumped version to $NEW_VERSION (committed locally)" + exit 0 + fi + + # Try push with retry logic for race conditions + for i in 1 2 3; do + if git push; then + echo "Successfully bumped version to $NEW_VERSION" + exit 0 + else + echo "Version bump push attempt $i failed, retrying..." + if [ $i -eq 3 ]; then + echo "Final version bump push attempt failed - another job may have bumped version" + git pull --rebase || true + git push || echo "Version bump recovery push also failed" + fi + sleep 2 + fi + done + else + echo "No version changes to commit" + fi +fi \ No newline at end of file diff --git a/scripts/update-all-badges.sh b/scripts/update-all-badges.sh new file mode 100755 index 0000000..05edb10 --- /dev/null +++ b/scripts/update-all-badges.sh @@ -0,0 +1,61 @@ +#!/bin/bash +# Simple script to update coverage badges in README.md +# Usage: ./scripts/update-all-badges.sh [bdd_coverage] [unit_coverage] +# Both parameters are optional - only updates what's provided + +set -e + +BDD_COVERAGE="" +UNIT_COVERAGE="" + +# Parse arguments (both optional) +if [ -n "$1" ]; then + BDD_COVERAGE=$1 +fi + +if [ -n "$2" ]; then + UNIT_COVERAGE=$2 +fi + +echo "đŸŽ¯ Updating coverage badges..." +if [ -n "$BDD_COVERAGE" ]; then + echo " BDD: ${BDD_COVERAGE}%" +fi +if [ -n "$UNIT_COVERAGE" ]; then + echo " Unit: ${UNIT_COVERAGE}%" +fi + +# Cross-platform sed command +# Detect if we're on macOS (BSD sed) or Linux (GNU sed) +SED_CMD="" +if [[ "$(uname)" == "Darwin" ]]; then + # macOS - requires empty string after -i + SED_CMD="sed -i ''" +else + # Linux - standard GNU sed + SED_CMD="sed -i" +fi + +# Update BDD coverage badge if provided +if [ -n "$BDD_COVERAGE" ] && grep -q "BDD_Coverage" README.md; then + $SED_CMD "s/BDD_Coverage-[0-9.]\+-%/BDD_Coverage-${BDD_COVERAGE}-%/g" README.md + echo "✅ BDD coverage badge updated to ${BDD_COVERAGE}%" +fi + +# Update Unit coverage badge if provided +if [ -n "$UNIT_COVERAGE" ] && grep -q "Unit_Coverage" README.md; then + $SED_CMD "s/Unit_Coverage-[0-9.]\+-%/Unit_Coverage-${UNIT_COVERAGE}-%/g" README.md + echo "✅ Unit coverage badge updated to ${UNIT_COVERAGE}%" +fi + +# Update main coverage badge if BDD coverage provided +if [ -n "$BDD_COVERAGE" ] && grep -q "coverage-[0-9.]\+-%" README.md; then + $SED_CMD "s/coverage-[0-9.]\+-%/coverage-${BDD_COVERAGE}-%/g" README.md + echo "✅ Main coverage badge updated to ${BDD_COVERAGE}%" +fi + +if [ -z "$BDD_COVERAGE" ] && [ -z "$UNIT_COVERAGE" ]; then + echo "â„šī¸ No coverage values provided - nothing to update" +fi + +echo "🎉 Badge update process completed!"