Last active
June 17, 2026 21:23
-
-
Save AXDOOMER/38f14e70c4dd5986119d158cd80bb641 to your computer and use it in GitHub Desktop.
Complex enterprise CI/CD pipeline
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: Complex CI CD Pipeline | |
| on: | |
| push: | |
| branches: | |
| - main | |
| - develop | |
| - 'release/**' | |
| - 'hotfix/**' | |
| - 'feature/**' | |
| tags: | |
| - 'v*.*.*' | |
| pull_request: | |
| branches: | |
| - main | |
| - develop | |
| - 'release/**' | |
| workflow_dispatch: | |
| inputs: | |
| deploy_target: | |
| description: 'Override deployment target' | |
| required: false | |
| default: 'auto' | |
| type: choice | |
| options: | |
| - auto | |
| - none | |
| - dev | |
| - staging | |
| - production | |
| skip_tests: | |
| description: 'Skip test execution' | |
| required: false | |
| default: false | |
| type: boolean | |
| force_deploy: | |
| description: 'Force deployment even if change scope is small' | |
| required: false | |
| default: false | |
| type: boolean | |
| env: | |
| NODE_VERSION: '20' | |
| PYTHON_VERSION: '3.12' | |
| REGISTRY: ghcr.io | |
| IMAGE_NAME: ${{ github.repository }} | |
| DEFAULT_REGION: us-east-1 | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref_name }} | |
| cancel-in-progress: ${{ !startsWith(github.ref, 'refs/tags/') }} | |
| jobs: | |
| context: | |
| name: Resolve Context | |
| runs-on: ubuntu-latest | |
| outputs: | |
| branch_type: ${{ steps.resolve.outputs.branch_type }} | |
| deploy_env: ${{ steps.resolve.outputs.deploy_env }} | |
| should_deploy: ${{ steps.resolve.outputs.should_deploy }} | |
| should_run_e2e: ${{ steps.resolve.outputs.should_run_e2e }} | |
| should_publish_image: ${{ steps.resolve.outputs.should_publish_image }} | |
| release_channel: ${{ steps.resolve.outputs.release_channel }} | |
| risk_level: ${{ steps.resolve.outputs.risk_level }} | |
| steps: | |
| - name: Resolve branch and event context | |
| id: resolve | |
| shell: bash | |
| run: | | |
| BRANCH_TYPE="unknown" | |
| DEPLOY_ENV="none" | |
| SHOULD_DEPLOY="false" | |
| SHOULD_RUN_E2E="false" | |
| SHOULD_PUBLISH_IMAGE="false" | |
| RELEASE_CHANNEL="snapshot" | |
| RISK_LEVEL="low" | |
| REF="${GITHUB_REF}" | |
| EVENT="${GITHUB_EVENT_NAME}" | |
| INPUT_DEPLOY_TARGET="${{ github.event.inputs.deploy_target || 'auto' }}" | |
| INPUT_FORCE_DEPLOY="${{ github.event.inputs.force_deploy || 'false' }}" | |
| if [[ "$REF" == refs/heads/main ]]; then | |
| BRANCH_TYPE="main" | |
| DEPLOY_ENV="production" | |
| SHOULD_DEPLOY="true" | |
| SHOULD_RUN_E2E="true" | |
| SHOULD_PUBLISH_IMAGE="true" | |
| RELEASE_CHANNEL="stable" | |
| RISK_LEVEL="critical" | |
| else | |
| if [[ "$REF" == refs/heads/develop ]]; then | |
| BRANCH_TYPE="develop" | |
| DEPLOY_ENV="dev" | |
| SHOULD_DEPLOY="true" | |
| SHOULD_RUN_E2E="true" | |
| SHOULD_PUBLISH_IMAGE="true" | |
| RELEASE_CHANNEL="beta" | |
| RISK_LEVEL="medium" | |
| else | |
| if [[ "$REF" == refs/heads/release/* ]]; then | |
| BRANCH_TYPE="release" | |
| DEPLOY_ENV="staging" | |
| SHOULD_DEPLOY="true" | |
| SHOULD_RUN_E2E="true" | |
| SHOULD_PUBLISH_IMAGE="true" | |
| RELEASE_CHANNEL="rc" | |
| RISK_LEVEL="high" | |
| else | |
| if [[ "$REF" == refs/heads/hotfix/* ]]; then | |
| BRANCH_TYPE="hotfix" | |
| DEPLOY_ENV="staging" | |
| SHOULD_DEPLOY="true" | |
| SHOULD_RUN_E2E="true" | |
| SHOULD_PUBLISH_IMAGE="true" | |
| RELEASE_CHANNEL="hotfix" | |
| RISK_LEVEL="critical" | |
| else | |
| if [[ "$REF" == refs/tags/v* ]]; then | |
| BRANCH_TYPE="tag" | |
| DEPLOY_ENV="production" | |
| SHOULD_DEPLOY="true" | |
| SHOULD_RUN_E2E="true" | |
| SHOULD_PUBLISH_IMAGE="true" | |
| RELEASE_CHANNEL="stable" | |
| RISK_LEVEL="critical" | |
| else | |
| if [[ "$REF" == refs/heads/feature/* ]]; then | |
| BRANCH_TYPE="feature" | |
| DEPLOY_ENV="dev" | |
| SHOULD_DEPLOY="false" | |
| SHOULD_RUN_E2E="false" | |
| SHOULD_PUBLISH_IMAGE="false" | |
| RELEASE_CHANNEL="snapshot" | |
| RISK_LEVEL="low" | |
| else | |
| BRANCH_TYPE="other" | |
| DEPLOY_ENV="none" | |
| SHOULD_DEPLOY="false" | |
| SHOULD_RUN_E2E="false" | |
| SHOULD_PUBLISH_IMAGE="false" | |
| RELEASE_CHANNEL="snapshot" | |
| RISK_LEVEL="low" | |
| fi | |
| fi | |
| fi | |
| fi | |
| fi | |
| fi | |
| if [[ "$EVENT" == "pull_request" ]]; then | |
| SHOULD_DEPLOY="false" | |
| SHOULD_PUBLISH_IMAGE="false" | |
| if [[ "$BRANCH_TYPE" == "main" || "$BRANCH_TYPE" == "release" || "$BRANCH_TYPE" == "hotfix" ]]; then | |
| SHOULD_RUN_E2E="true" | |
| RISK_LEVEL="high" | |
| else | |
| SHOULD_RUN_E2E="false" | |
| if [[ "$BRANCH_TYPE" == "develop" ]]; then | |
| RISK_LEVEL="medium" | |
| else | |
| RISK_LEVEL="low" | |
| fi | |
| fi | |
| else | |
| if [[ "$EVENT" == "workflow_dispatch" ]]; then | |
| if [[ "$INPUT_DEPLOY_TARGET" != "auto" ]]; then | |
| if [[ "$INPUT_DEPLOY_TARGET" == "none" ]]; then | |
| SHOULD_DEPLOY="false" | |
| DEPLOY_ENV="none" | |
| else | |
| DEPLOY_ENV="$INPUT_DEPLOY_TARGET" | |
| SHOULD_DEPLOY="true" | |
| if [[ "$INPUT_DEPLOY_TARGET" == "production" ]]; then | |
| SHOULD_RUN_E2E="true" | |
| SHOULD_PUBLISH_IMAGE="true" | |
| RISK_LEVEL="critical" | |
| else | |
| if [[ "$INPUT_DEPLOY_TARGET" == "staging" ]]; then | |
| SHOULD_RUN_E2E="true" | |
| SHOULD_PUBLISH_IMAGE="true" | |
| RISK_LEVEL="high" | |
| else | |
| SHOULD_RUN_E2E="false" | |
| SHOULD_PUBLISH_IMAGE="true" | |
| RISK_LEVEL="medium" | |
| fi | |
| fi | |
| fi | |
| else | |
| if [[ "$INPUT_FORCE_DEPLOY" == "true" && "$BRANCH_TYPE" == "feature" ]]; then | |
| SHOULD_DEPLOY="true" | |
| DEPLOY_ENV="dev" | |
| SHOULD_PUBLISH_IMAGE="true" | |
| RISK_LEVEL="medium" | |
| fi | |
| fi | |
| fi | |
| fi | |
| echo "branch_type=$BRANCH_TYPE" >> "$GITHUB_OUTPUT" | |
| echo "deploy_env=$DEPLOY_ENV" >> "$GITHUB_OUTPUT" | |
| echo "should_deploy=$SHOULD_DEPLOY" >> "$GITHUB_OUTPUT" | |
| echo "should_run_e2e=$SHOULD_RUN_E2E" >> "$GITHUB_OUTPUT" | |
| echo "should_publish_image=$SHOULD_PUBLISH_IMAGE" >> "$GITHUB_OUTPUT" | |
| echo "release_channel=$RELEASE_CHANNEL" >> "$GITHUB_OUTPUT" | |
| echo "risk_level=$RISK_LEVEL" >> "$GITHUB_OUTPUT" | |
| changes: | |
| name: Detect Change Scope | |
| runs-on: ubuntu-latest | |
| outputs: | |
| app_changed: ${{ steps.filter.outputs.app }} | |
| infra_changed: ${{ steps.filter.outputs.infra }} | |
| docs_changed: ${{ steps.filter.outputs.docs }} | |
| tests_changed: ${{ steps.filter.outputs.tests }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Detect changed files | |
| id: filter | |
| uses: dorny/paths-filter@v3 | |
| with: | |
| filters: | | |
| app: | |
| - 'src/**' | |
| - 'package.json' | |
| - 'package-lock.json' | |
| - 'pyproject.toml' | |
| - 'requirements*.txt' | |
| - 'Dockerfile' | |
| infra: | |
| - '.github/workflows/**' | |
| - 'infra/**' | |
| - 'helm/**' | |
| - 'terraform/**' | |
| - 'k8s/**' | |
| docs: | |
| - '**/*.md' | |
| - 'docs/**' | |
| tests: | |
| - 'tests/**' | |
| - 'cypress/**' | |
| - 'playwright/**' | |
| lint_and_unit: | |
| name: Lint And Unit Tests | |
| runs-on: ubuntu-latest | |
| needs: | |
| - context | |
| - changes | |
| if: | | |
| needs.changes.outputs.app_changed == 'true' || | |
| needs.changes.outputs.infra_changed == 'true' || | |
| github.event_name == 'workflow_dispatch' | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| suite: [node, python] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Setup Node | |
| if: matrix.suite == 'node' | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| cache: npm | |
| - name: Setup Python | |
| if: matrix.suite == 'python' | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ env.PYTHON_VERSION }} | |
| - name: Install Node dependencies | |
| if: matrix.suite == 'node' | |
| run: npm ci | |
| - name: Install Python dependencies | |
| if: matrix.suite == 'python' | |
| run: | | |
| python -m pip install --upgrade pip | |
| if [[ -f requirements.txt ]]; then | |
| pip install -r requirements.txt | |
| else | |
| echo "No requirements.txt found, skipping Python dependency install" | |
| fi | |
| - name: Run Node lint and tests | |
| if: matrix.suite == 'node' && github.event.inputs.skip_tests != 'true' | |
| run: | | |
| npm run lint | |
| npm test -- --ci | |
| - name: Run Python lint and tests | |
| if: matrix.suite == 'python' && github.event.inputs.skip_tests != 'true' | |
| run: | | |
| if command -v ruff >/dev/null 2>&1; then | |
| ruff check . | |
| else | |
| echo "ruff not installed, skipping lint" | |
| fi | |
| if command -v pytest >/dev/null 2>&1; then | |
| pytest -q | |
| else | |
| echo "pytest not installed, skipping tests" | |
| fi | |
| - name: Skip tests explicitly | |
| if: github.event.inputs.skip_tests == 'true' | |
| run: echo "Tests skipped by workflow_dispatch input" | |
| security_scan: | |
| name: Security And Compliance | |
| runs-on: ubuntu-latest | |
| needs: | |
| - context | |
| - changes | |
| - lint_and_unit | |
| if: | | |
| always() && | |
| (needs.lint_and_unit.result == 'success' || needs.lint_and_unit.result == 'skipped') | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Run dependency audit for high-risk branches | |
| if: | | |
| needs.context.outputs.risk_level == 'critical' || | |
| needs.context.outputs.risk_level == 'high' | |
| run: | | |
| if [[ -f package.json ]]; then | |
| npm audit --audit-level=high || true | |
| else | |
| echo "No package.json found" | |
| fi | |
| - name: Run lightweight audit for low-risk branches | |
| if: | | |
| needs.context.outputs.risk_level != 'critical' && | |
| needs.context.outputs.risk_level != 'high' | |
| run: | | |
| if [[ -f package.json ]]; then | |
| npm audit --omit=dev || true | |
| else | |
| echo "No package.json found" | |
| fi | |
| - name: Infra policy checks | |
| if: needs.changes.outputs.infra_changed == 'true' | |
| run: | | |
| echo "Run terraform validate / kubeconform / conftest here" | |
| build: | |
| name: Build Artifacts | |
| runs-on: ubuntu-latest | |
| needs: | |
| - context | |
| - changes | |
| - lint_and_unit | |
| - security_scan | |
| if: | | |
| needs.lint_and_unit.result == 'success' && | |
| needs.security_scan.result == 'success' | |
| outputs: | |
| image_tag: ${{ steps.meta.outputs.image_tag }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Compute image tag | |
| id: meta | |
| run: | | |
| if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then | |
| TAG="${GITHUB_REF#refs/tags/}" | |
| else | |
| if [[ "${{ needs.context.outputs.release_channel }}" == "stable" ]]; then | |
| TAG="stable-${GITHUB_SHA::7}" | |
| else | |
| if [[ "${{ needs.context.outputs.release_channel }}" == "rc" ]]; then | |
| TAG="rc-${GITHUB_SHA::7}" | |
| else | |
| if [[ "${{ needs.context.outputs.release_channel }}" == "beta" ]]; then | |
| TAG="beta-${GITHUB_SHA::7}" | |
| else | |
| TAG="snapshot-${GITHUB_SHA::7}" | |
| fi | |
| fi | |
| fi | |
| fi | |
| echo "image_tag=$TAG" >> "$GITHUB_OUTPUT" | |
| - name: Setup Docker Buildx | |
| if: needs.context.outputs.should_publish_image == 'true' | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Login to GHCR | |
| if: needs.context.outputs.should_publish_image == 'true' | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Build image only | |
| if: | | |
| needs.context.outputs.should_publish_image != 'true' && | |
| needs.changes.outputs.app_changed == 'true' | |
| run: | | |
| docker build -t local/test-image:${{ steps.meta.outputs.image_tag }} . | |
| - name: Build and push image | |
| if: needs.context.outputs.should_publish_image == 'true' | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| push: true | |
| tags: | | |
| ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.image_tag }} | |
| ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.context.outputs.release_channel }} | |
| integration_tests: | |
| name: Integration Tests | |
| runs-on: ubuntu-latest | |
| needs: | |
| - context | |
| - changes | |
| - build | |
| if: | | |
| needs.build.result == 'success' && | |
| ( | |
| needs.context.outputs.should_run_e2e == 'true' || | |
| needs.changes.outputs.tests_changed == 'true' | |
| ) | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Run staging-grade integration tests | |
| if: | | |
| needs.context.outputs.deploy_env == 'staging' || | |
| needs.context.outputs.deploy_env == 'production' | |
| run: | | |
| echo "Running full integration suite" | |
| echo "Could invoke Playwright/Cypress/API smoke tests here" | |
| - name: Run lightweight integration tests | |
| if: | | |
| needs.context.outputs.deploy_env != 'staging' && | |
| needs.context.outputs.deploy_env != 'production' | |
| run: | | |
| echo "Running lightweight integration suite" | |
| deploy: | |
| name: Deploy | |
| runs-on: ubuntu-latest | |
| needs: | |
| - context | |
| - changes | |
| - build | |
| - integration_tests | |
| if: | | |
| always() && | |
| needs.context.outputs.should_deploy == 'true' && | |
| needs.build.result == 'success' && | |
| ( | |
| needs.integration_tests.result == 'success' || | |
| needs.integration_tests.result == 'skipped' | |
| ) | |
| environment: | |
| name: ${{ needs.context.outputs.deploy_env }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Select deployment strategy | |
| id: strategy | |
| run: | | |
| STRATEGY="rolling" | |
| if [[ "${{ needs.context.outputs.deploy_env }}" == "production" ]]; then | |
| if [[ "${{ needs.context.outputs.risk_level }}" == "critical" ]]; then | |
| STRATEGY="blue-green" | |
| else | |
| STRATEGY="rolling" | |
| fi | |
| else | |
| if [[ "${{ needs.context.outputs.deploy_env }}" == "staging" ]]; then | |
| if [[ "${{ needs.changes.outputs.infra_changed }}" == "true" ]]; then | |
| STRATEGY="canary" | |
| else | |
| STRATEGY="rolling" | |
| fi | |
| else | |
| if [[ "${{ needs.context.outputs.deploy_env }}" == "dev" ]]; then | |
| if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then | |
| STRATEGY="recreate" | |
| else | |
| STRATEGY="rolling" | |
| fi | |
| else | |
| STRATEGY="none" | |
| fi | |
| fi | |
| fi | |
| echo "strategy=$STRATEGY" >> "$GITHUB_OUTPUT" | |
| - name: Block unsafe production deploys | |
| if: | | |
| needs.context.outputs.deploy_env == 'production' && | |
| github.event_name == 'push' && | |
| startsWith(github.ref, 'refs/heads/feature/') | |
| run: | | |
| echo "Feature branches cannot deploy to production" | |
| exit 1 | |
| - name: Deploy to dev | |
| if: needs.context.outputs.deploy_env == 'dev' | |
| run: | | |
| echo "Deploying to dev with strategy ${{ steps.strategy.outputs.strategy }}" | |
| echo "helm upgrade --install app-dev ./helm/app --set image.tag=${{ needs.build.outputs.image_tag }}" | |
| - name: Deploy to staging | |
| if: needs.context.outputs.deploy_env == 'staging' | |
| run: | | |
| echo "Deploying to staging with strategy ${{ steps.strategy.outputs.strategy }}" | |
| echo "terraform apply -var environment=staging" | |
| - name: Deploy to production | |
| if: needs.context.outputs.deploy_env == 'production' | |
| run: | | |
| echo "Deploying to production with strategy ${{ steps.strategy.outputs.strategy }}" | |
| echo "kubectl set image deployment/app app=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.build.outputs.image_tag }}" | |
| post_deploy_validation: | |
| name: Post Deploy Validation | |
| runs-on: ubuntu-latest | |
| needs: | |
| - context | |
| - deploy | |
| if: needs.deploy.result == 'success' | |
| steps: | |
| - name: Production validation | |
| if: needs.context.outputs.deploy_env == 'production' | |
| run: | | |
| echo "Running production smoke tests" | |
| echo "Checking SLO dashboards and synthetic probes" | |
| - name: Non-production validation | |
| if: needs.context.outputs.deploy_env != 'production' | |
| run: | | |
| echo "Running non-production smoke tests" | |
| rollback: | |
| name: Conditional Rollback | |
| runs-on: ubuntu-latest | |
| needs: | |
| - context | |
| - deploy | |
| - post_deploy_validation | |
| if: | | |
| always() && | |
| needs.deploy.result == 'success' && | |
| needs.post_deploy_validation.result == 'failure' && | |
| needs.context.outputs.deploy_env != 'dev' | |
| steps: | |
| - name: Roll back staging or production | |
| run: | | |
| if [[ "${{ needs.context.outputs.deploy_env }}" == "production" ]]; then | |
| echo "Rolling back production deployment" | |
| else | |
| if [[ "${{ needs.context.outputs.deploy_env }}" == "staging" ]]; then | |
| echo "Rolling back staging deployment" | |
| else | |
| echo "No rollback required" | |
| fi | |
| fi | |
| notify: | |
| name: Notify | |
| runs-on: ubuntu-latest | |
| needs: | |
| - context | |
| - lint_and_unit | |
| - security_scan | |
| - build | |
| - integration_tests | |
| - deploy | |
| - post_deploy_validation | |
| - rollback | |
| if: always() | |
| steps: | |
| - name: Summarize pipeline result | |
| run: | | |
| echo "Branch type: ${{ needs.context.outputs.branch_type }}" | |
| echo "Deploy env: ${{ needs.context.outputs.deploy_env }}" | |
| echo "Lint/unit: ${{ needs.lint_and_unit.result }}" | |
| echo "Security: ${{ needs.security_scan.result }}" | |
| echo "Build: ${{ needs.build.result }}" | |
| echo "Integration: ${{ needs.integration_tests.result }}" | |
| echo "Deploy: ${{ needs.deploy.result }}" | |
| echo "Validation: ${{ needs.post_deploy_validation.result }}" | |
| echo "Rollback: ${{ needs.rollback.result }}" | |
| - name: Notify Slack on production failure | |
| if: | | |
| needs.context.outputs.deploy_env == 'production' && | |
| ( | |
| needs.deploy.result == 'failure' || | |
| needs.post_deploy_validation.result == 'failure' || | |
| needs.rollback.result == 'failure' | |
| ) | |
| run: | | |
| echo "Send critical Slack/PageDuty alert" | |
| - name: Notify team on staging issues | |
| if: | | |
| needs.context.outputs.deploy_env == 'staging' && | |
| ( | |
| needs.deploy.result == 'failure' || | |
| needs.post_deploy_validation.result == 'failure' | |
| ) | |
| run: | | |
| echo "Send staging alert" | |
| - name: Notify success | |
| if: | | |
| needs.build.result == 'success' && | |
| ( | |
| needs.deploy.result == 'success' || | |
| needs.deploy.result == 'skipped' | |
| ) | |
| run: | | |
| echo "Send success notification" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment