From e39ed36fcc30719f177ddf55bdd8fbd8fc9a93ec Mon Sep 17 00:00:00 2001 From: Ashwin Kumar Date: Fri, 10 Apr 2026 05:17:56 +0200 Subject: [PATCH] feat(woodpecker): update CI pipeline with change detection and selective builds - Update .woodpecker.yml with change detection step - Add optimized Dockerfile.optimized support - Add deployment step to Kubernetes - Add woodpecker-local-build.sh for local testing - Only build and deploy services with code changes - Skip unchanged services for faster pipelines --- .woodpecker.yml | 125 ++++++++++++++++++++++++--- scripts/woodpecker-local-build.sh | 137 ++++++++++++++++++++++++++++++ 2 files changed, 251 insertions(+), 11 deletions(-) create mode 100755 scripts/woodpecker-local-build.sh diff --git a/.woodpecker.yml b/.woodpecker.yml index 1b8d48c..6be88d3 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -1,5 +1,5 @@ when: - branch: high-performance + branch: [main, high-performance] event: push matrix: @@ -24,24 +24,127 @@ matrix: - cron steps: - - name: build-and-push + # Step 1: Detect if this service needs building + - name: detect-changes + image: alpine/git + commands: + - apk add --no-cache bash + - | + #!/bin/bash + set -e + + # Get changed files from last commit + CHANGED_FILES=$(git diff --name-only HEAD~1 HEAD || echo "") + + # Convert matrix SERVICE to path format + SERVICE_PATH=$(echo "${SERVICE}" | tr '_' '-') + + # Check if shared crates changed (triggers all services) + SHARED_CHANGED=false + if echo "$CHANGED_FILES" | grep -q "^crates/"; then + SHARED_CHANGED=true + echo "⚠️ Shared crates changed - will build all services" + fi + + # Check if this specific service changed + SERVICE_CHANGED=false + if echo "$CHANGED_FILES" | grep -q "^apps/${SERVICE_PATH}/"; then + SERVICE_CHANGED=true + echo "✅ Service ${SERVICE} has code changes" + fi + + # Create marker file + if [ "$SHARED_CHANGED" = "true" ] || [ "$SERVICE_CHANGED" = "true" ]; then + echo "SHOULD_BUILD=true" > .build-${SERVICE} + echo "🚀 Will build ${SERVICE}" + else + echo "SHOULD_BUILD=false" > .build-${SERVICE} + echo "⏭️ Skipping ${SERVICE} - no changes detected" + fi + + # Export for other steps + cat .build-${SERVICE} >> ${CI_ENV} + + # Step 2: Build optimized Docker image (only if changed) + - name: build image: woodpeckerci/plugin-docker-buildx:5.0.0 settings: registry: ghcr.io repo: ghcr.io/traceworks2023/nxtgauge-rust-${SERVICE} context: . - dockerfile: apps/${SERVICE}/Dockerfile + dockerfile: Dockerfile.optimized + build_args: + - SERVICE_NAME=${SERVICE} tags: + - ${CI_COMMIT_SHA} + - latest - high-performance-latest logins: - - registry: https://index.docker.io/v1/ + - registry: https://ghcr.io username: - from_secret: DOCKERHUB_USERNAME + from_secret: GHCR_USERNAME password: - from_secret: DOCKERHUB_TOKEN - username: - from_secret: GHCR_USERNAME - password: - from_secret: GHCR_TOKEN + from_secret: GHCR_TOKEN platforms: linux/amd64 - + when: + - evaluate: 'env.SHOULD_BUILD == "true"' + + # Step 3: Deploy to Kubernetes (only if changed and on main/high-performance) + - name: deploy + image: bitnami/kubectl:latest + secrets: [kube_config] + commands: + - | + #!/bin/bash + set -e + + # Check if we should deploy + if [ "${SHOULD_BUILD}" != "true" ]; then + echo "⏭️ Skipping deployment for ${SERVICE} - no changes" + exit 0 + fi + + # Setup kubeconfig + mkdir -p ~/.kube + echo "$KUBE_CONFIG" | base64 -d > ~/.kube/config + chmod 600 ~/.kube/config + + # Convert service name to Kubernetes deployment name + DEPLOYMENT_NAME=$(echo "${SERVICE}" | tr '_' '-') + NAMESPACE="nxtgauge" + + echo "🚀 Deploying ${SERVICE} (deployment: nxtgauge-rust-${DEPLOYMENT_NAME})..." + + # Trigger rolling restart to pick up new image + kubectl rollout restart deployment/nxtgauge-rust-${DEPLOYMENT_NAME} -n ${NAMESPACE} + + # Wait for rollout to complete (with timeout) + echo "⏳ Waiting for rollout to complete..." + kubectl rollout status deployment/nxtgauge-rust-${DEPLOYMENT_NAME} -n ${NAMESPACE} --timeout=300s + + echo "✅ ${SERVICE} deployed successfully!" + + # Show deployment status + kubectl get deployment/nxtgauge-rust-${DEPLOYMENT_NAME} -n ${NAMESPACE} + when: + - evaluate: 'env.SHOULD_BUILD == "true"' + - branch: [main, high-performance] + + # Step 4: Notify on success + - name: notify-success + image: alpine:latest + commands: + - echo "✅ Pipeline completed successfully for ${SERVICE}" + when: + - evaluate: 'env.SHOULD_BUILD == "true"' + - status: success + + # Step 5: Notify on failure + - name: notify-failure + image: alpine:latest + commands: + - echo "❌ Pipeline failed for ${SERVICE}" + - echo "Check logs for details" + when: + - evaluate: 'env.SHOULD_BUILD == "true"' + - status: failure diff --git a/scripts/woodpecker-local-build.sh b/scripts/woodpecker-local-build.sh new file mode 100755 index 0000000..a73101a --- /dev/null +++ b/scripts/woodpecker-local-build.sh @@ -0,0 +1,137 @@ +#!/bin/bash +# woodpecker-local-build.sh - Local testing of Woodpecker pipeline +# Builds only changed services locally (no Woodpecker server needed) + +set -e + +REGISTRY="ghcr.io/traceworks2023" +VERSION=${VERSION:-$(git rev-parse --short HEAD)} + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +SERVICES=( + "gateway" + "users" + "companies" + "job_seekers" + "customers" + "payments" + "employees" + "photographers" + "makeup_artists" + "tutors" + "developers" + "video_editors" + "graphic_designers" + "social_media_managers" + "fitness_trainers" + "catering_services" + "ugc_content_creators" + "cron" +) + +echo -e "${BLUE}🔍 Nxtgauge Local Build Script (Woodpecker Compatible)${NC}" +echo "=============================================" + +# Get changed files +CHANGED_FILES=$(git diff --name-only HEAD~1 HEAD 2>/dev/null || echo "") + +if [ -z "$CHANGED_FILES" ]; then + echo -e "${YELLOW}⚠️ No changes detected. Building all services...${NC}" + BUILD_ALL=true +else + BUILD_ALL=false + echo "Changed files:" + echo "$CHANGED_FILES" | head -10 + if [ $(echo "$CHANGED_FILES" | wc -l) -gt 10 ]; then + echo "... and more" + fi +fi + +# Check if shared crates changed +SHARED_CHANGED=false +if echo "$CHANGED_FILES" | grep -q "^crates/"; then + SHARED_CHANGED=true + echo -e "${YELLOW}⚠️ Shared crates changed - will build all services${NC}" + BUILD_ALL=true +fi + +# Function to build a service +build_service() { + local service=$1 + local tag="${REGISTRY}/nxtgauge-rust-${service}:${VERSION}" + local latest="${REGISTRY}/nxtgauge-rust-${service}:latest" + + echo "" + echo -e "${BLUE}🔨 Building ${service}...${NC}" + + # Build with optimized Dockerfile + if docker build \ + --build-arg SERVICE_NAME=${service} \ + -f Dockerfile.optimized \ + -t ${tag} \ + -t ${latest} \ + . 2>&1; then + + echo -e "${GREEN}✅ ${service} built successfully${NC}" + echo " Image: ${tag}" + + # Show image size + SIZE=$(docker images --format "{{.Size}}" ${tag}) + echo " Size: ${SIZE}" + + return 0 + else + echo -e "${RED}❌ ${service} build failed${NC}" + return 1 + fi +} + +# Track results +BUILT=0 +SKIPPED=0 +FAILED=0 + +# Build each service +for service in "${SERVICES[@]}"; do + SERVICE_PATH=$(echo "$service" | tr '_' '-') + + if [ "$BUILD_ALL" = true ]; then + SHOULD_BUILD=true + else + # Check if this service changed + if echo "$CHANGED_FILES" | grep -q "^apps/${SERVICE_PATH}/"; then + SHOULD_BUILD=true + else + SHOULD_BUILD=false + fi + fi + + if [ "$SHOULD_BUILD" = true ]; then + if build_service "$service"; then + BUILT=$((BUILT + 1)) + else + FAILED=$((FAILED + 1)) + fi + else + echo -e "${YELLOW}⏭️ ${service} - no changes, skipping${NC}" + SKIPPED=$((SKIPPED + 1)) + fi +done + +echo "" +echo "=============================================" +echo -e "${GREEN}✅ Built: ${BUILT}${NC}" +echo -e "${YELLOW}⏭️ Skipped: ${SKIPPED}${NC}" + +if [ $FAILED -gt 0 ]; then + echo -e "${RED}❌ Failed: ${FAILED}${NC}" + exit 1 +else + echo -e "${GREEN}🎉 All builds successful!${NC}" +fi