# Woodpecker CI/CD Pipeline - Peikarband Landing # Application build pipeline (uses pre-built base image) variables: - &python_image 'python:3.11-slim' - &helm_image 'alpine/helm:latest' - &base_image 'hub.peikarband.ir/peikarband/base:latest' when: - event: [push, pull_request, tag, manual] pipeline: # ============================================ # Stage 1: Check Base Image Availability # ============================================ check-base-image: image: alpine:latest commands: - apk add --no-cache curl - | echo "Checking if base image is available..." REGISTRY="hub.peikarband.ir" REPO="peikarband/base" TAG="latest" if curl -f -u "$HARBOR_USERNAME:$HARBOR_PASSWORD" \ "https://$REGISTRY/v2/$REPO/manifests/$TAG" > /dev/null 2>&1; then echo "✓ Base image found: $REGISTRY/$REPO:$TAG" else echo "❌ Base image not found!" echo "Please run .woodpecker-base.yml pipeline first to build base image" echo "Or trigger it manually in Woodpecker UI" exit 1 fi secrets: [HARBOR_USERNAME, HARBOR_PASSWORD] when: - event: [push, tag] # ============================================ # Stage 2: Build Application Image # ============================================ build-image: image: woodpeckerci/plugin-docker-buildx settings: registry: hub.peikarband.ir repo: hub.peikarband.ir/peikarband/landing username: from_secret: HARBOR_USERNAME password: from_secret: HARBOR_PASSWORD dockerfile: docker/Dockerfile context: . platforms: linux/amd64 # استفاده از base image build_args: - BASE_IMAGE=hub.peikarband.ir/peikarband/base:latest - VERSION=${CI_COMMIT_SHA:0:8} - BUILD_DATE=${CI_PIPELINE_CREATED} # فقط build می‌کنیم، بدون push tags: - ${CI_COMMIT_SHA:0:8} labels: - org.opencontainers.image.created=${CI_PIPELINE_CREATED} - org.opencontainers.image.source=${CI_REPO_LINK} - org.opencontainers.image.url=${CI_REPO_LINK} - org.opencontainers.image.revision=${CI_COMMIT_SHA} - org.opencontainers.image.version=${CI_COMMIT_SHA:0:8} - org.opencontainers.image.title=Peikarband Landing - org.opencontainers.image.description=Peikarband hosting platform landing page cache_from: type=registry,ref=hub.peikarband.ir/peikarband/landing:buildcache cache_to: type=inline provenance: false # فقط build، بدون push push: false load: false when: - event: [push, tag] branch: [main, develop] # ============================================ # Stage 3: Push Image with Multi-Tags # ============================================ push-image: image: woodpeckerci/plugin-docker-buildx settings: registry: hub.peikarband.ir repo: hub.peikarband.ir/peikarband/landing username: from_secret: HARBOR_USERNAME password: from_secret: HARBOR_PASSWORD dockerfile: docker/Dockerfile context: . platforms: linux/amd64 build_args: - BASE_IMAGE=hub.peikarband.ir/peikarband/base:latest - VERSION=${CI_COMMIT_SHA:0:8} - BUILD_DATE=${CI_PIPELINE_CREATED} # Multi-tagging strategy tags: - latest - ${CI_COMMIT_SHA:0:8} - ${CI_COMMIT_BRANCH} labels: - org.opencontainers.image.created=${CI_PIPELINE_CREATED} - org.opencontainers.image.source=${CI_REPO_LINK} - org.opencontainers.image.url=${CI_REPO_LINK} - org.opencontainers.image.revision=${CI_COMMIT_SHA} - org.opencontainers.image.version=${CI_COMMIT_SHA:0:8} - org.opencontainers.image.title=Peikarband Landing - org.opencontainers.image.description=Peikarband hosting platform landing page cache_from: type=registry,ref=hub.peikarband.ir/peikarband/landing:buildcache cache_to: type=inline provenance: false # حالا push می‌کنیم push: true when: - event: [push, tag] branch: [main, develop] # ============================================ # Stage 4: Verify Push # ============================================ verify-push: image: alpine:latest commands: - apk add --no-cache curl - | echo "Verifying image was pushed successfully..." sleep 3 # Wait for registry sync REGISTRY="hub.peikarband.ir" REPO="peikarband/landing" TAG="${CI_COMMIT_SHA:0:8}" if curl -f -u "$HARBOR_USERNAME:$HARBOR_PASSWORD" \ "https://$REGISTRY/v2/$REPO/manifests/$TAG" > /dev/null 2>&1; then echo "✓ Image verified: $REGISTRY/$REPO:$TAG" else echo "❌ Failed to verify image push" exit 1 fi secrets: [HARBOR_USERNAME, HARBOR_PASSWORD] when: - event: [push, tag] branch: [main, develop] # ============================================ # Stages below are commented for now # Uncomment when ready to use # ============================================ # # ============================================ # # Stage 1: Code Quality & Linting # # ============================================ # lint-flake8: # image: *python_image # commands: # - pip install --no-cache-dir flake8 # - cd peikarband # - flake8 src/ --count --select=E9,F63,F7,F82 --show-source --statistics # - flake8 src/ --count --max-complexity=10 --max-line-length=120 --statistics --exit-zero # when: # - event: [push, pull_request, tag] # lint-black: # image: *python_image # commands: # - pip install --no-cache-dir black # - cd peikarband # - black --check src/ || echo "⚠️ Black formatting issues found (non-blocking)" # when: # - event: [push, pull_request, tag] # lint-isort: # image: *python_image # commands: # - pip install --no-cache-dir isort # - cd peikarband # - isort --check-only src/ || echo "⚠️ Import sorting issues found (non-blocking)" # when: # - event: [push, pull_request, tag] # type-check: # image: *python_image # commands: # - pip install --no-cache-dir mypy types-redis types-requests # - cd peikarband # - mypy src/ --config-file=config/mypy.ini || echo "⚠️ Type checking issues found (non-blocking)" # when: # - event: [push, pull_request, tag] # # ============================================ # # Stage 2: Security Scanning # # ============================================ # security-bandit: # image: *python_image # commands: # - pip install --no-cache-dir bandit[toml] # - cd peikarband # - bandit -r src/ -f json -o bandit-report.json || true # - bandit -r src/ -ll || echo "⚠️ Security issues found (non-blocking)" # when: # - event: [push, pull_request, tag] # security-safety: # image: *python_image # commands: # - pip install --no-cache-dir safety # - cd peikarband # - safety check -r requirements.txt --json || echo "⚠️ Dependency vulnerabilities found (non-blocking)" # when: # - event: [push, pull_request, tag] # # ============================================ # # Stage 3: Testing # # ============================================ # test: # image: *python_image # commands: # - apt-get update && apt-get install -y --no-install-recommends curl # - pip install --no-cache-dir -r peikarband/requirements.txt # - pip install --no-cache-dir -r peikarband/requirements-dev.txt # - cd peikarband # - pytest tests/ -v --cov=src --cov-report=term-missing --cov-report=xml || echo "⚠️ Tests failed (non-blocking)" # when: # - event: [push, pull_request, tag] # # ============================================ # # Stage 4: Helm Validation # # ============================================ # helm-lint: # image: *helm_image # commands: # - helm version # - helm lint helm/peikarband # - echo "✓ Helm chart validation passed" # when: # - event: [push, pull_request, tag] # helm-template: # image: *helm_image # commands: # - helm template peikarband helm/peikarband -f helm/peikarband/values-production.yaml --debug > /dev/null # - echo "✓ Helm template rendering successful" # when: # - event: [push, pull_request, tag] # # ============================================ # # Stage 6: Deployment - Staging # # ============================================ # deploy-staging: # image: *helm_image # commands: # - apk add --no-cache kubectl # - echo "$KUBECONFIG_STAGING" | base64 -d > /tmp/kubeconfig # - export KUBECONFIG=/tmp/kubeconfig # - | # helm upgrade --install peikarband-staging helm/peikarband \ # --namespace staging \ # --create-namespace \ # --set image.repository=hub.peikarband.ir/peikarband/landing \ # --set image.tag=${CI_COMMIT_SHA:0:8} \ # --set image.pullPolicy=Always \ # --values helm/peikarband/values-staging.yaml \ # --wait \ # --timeout 5m # - kubectl get pods -n staging # - echo "✓ Deployed to staging successfully" # secrets: [KUBECONFIG_STAGING] # when: # - event: push # branch: [main, develop] # # ============================================ # # Stage 7: Deployment - Production # # ============================================ # deploy-production: # image: *helm_image # commands: # - apk add --no-cache kubectl # - echo "$KUBECONFIG_PRODUCTION" | base64 -d > /tmp/kubeconfig # - export KUBECONFIG=/tmp/kubeconfig # - | # helm upgrade --install peikarband helm/peikarband \ # --namespace production \ # --create-namespace \ # --set image.repository=hub.peikarband.ir/peikarband/landing \ # --set image.tag=${CI_COMMIT_TAG} \ # --set image.pullPolicy=Always \ # --values helm/peikarband/values-production.yaml \ # --wait \ # --timeout 10m # - kubectl rollout status deployment/peikarband -n production # - kubectl get pods -n production # - echo "✓ Deployed to production successfully" # secrets: [KUBECONFIG_PRODUCTION] # when: # - event: tag # ref: refs/tags/v* # ============================================ # Stage 8: Notifications # ============================================ notify-success: image: alpine:latest commands: - echo "🎉 Pipeline completed successfully!" - echo "Branch:" "${CI_COMMIT_BRANCH}" - echo "Commit:" "${CI_COMMIT_SHA:0:8}" - echo "Image:" "hub.peikarband.ir/peikarband/landing:${CI_COMMIT_SHA:0:8}" when: event: [push, tag] status: success notify-failure: image: alpine:latest commands: - echo "❌ Pipeline failed!" - echo "Branch:" "${CI_COMMIT_BRANCH}" - echo "Commit:" "${CI_COMMIT_SHA:0:8}" - echo "Please check the logs above" when: event: [push, tag] status: failure