CI/CD Pipeline #8
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: CI/CD Pipeline | |
| on: | |
| push: | |
| branches: | |
| - main | |
| - develop | |
| paths-ignore: | |
| - "**.md" | |
| - "docs/**" | |
| - "LICENSE" | |
| pull_request: | |
| branches: | |
| - main | |
| - develop | |
| paths-ignore: | |
| - "**.md" | |
| - "docs/**" | |
| - "LICENSE" | |
| schedule: | |
| # Run weekly security scans | |
| - cron: "0 2 * * 1" | |
| workflow_dispatch: | |
| env: | |
| ANSIBLE_FORCE_COLOR: "1" | |
| ANSIBLE_VERBOSITY: "1" | |
| PY_COLORS: "1" | |
| PYTHON_VERSIONS: "3.8, 3.9, 3.10, 3.11" | |
| ANSIBLE_VERSIONS: "core 2.12, 2.13, 2.14, 2.15" | |
| UBUNTU_VERSIONS: "20.04, 22.04, 24.04" | |
| jobs: | |
| # Job to determine which files have changed to optimize CI execution | |
| changes: | |
| name: Detect Changes | |
| runs-on: ubuntu-latest | |
| outputs: | |
| any: ${{ steps.changes.outputs.any_changed }} | |
| roles: ${{ steps.changes.outputs.roles_any_changed }} | |
| molecule: ${{ steps.changes.outputs.molecule_any_changed }} | |
| docs: ${{ steps.changes.outputs.docs_any_changed }} | |
| workflow: ${{ steps.changes.outputs.workflow_any_changed }} | |
| steps: | |
| - name: Checkout Code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Check for Changes | |
| id: changes | |
| uses: dorny/paths-filter@v3 | |
| with: | |
| filters: | | |
| roles: | |
| - 'roles/**' | |
| molecule: | |
| - 'molecule/**' | |
| docs: | |
| - '**/*.md' | |
| - 'docs/**' | |
| workflow: | |
| - '.github/workflows/**' | |
| - 'requirements.yml' | |
| - 'ansible.cfg' | |
| - '.ansible-lint' | |
| # Linting job to validate code quality and syntax | |
| lint: | |
| name: Linting | |
| runs-on: ubuntu-latest | |
| needs: changes | |
| if: needs.changes.outputs.any == 'true' || needs.changes.outputs.workflow == 'true' | |
| strategy: | |
| matrix: | |
| python-version: [3.9] | |
| ansible-core-version: ["2.15"] | |
| steps: | |
| - name: Checkout Code | |
| uses: actions/checkout@v4 | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Cache Python Dependencies | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.cache/pip | |
| key: ${{ runner.os }}-pip-${{ matrix.python-version }}-${{ hashFiles('**/requirements.yml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pip-${{ matrix.python-version }}- | |
| - name: Install Dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install "ansible-core==${{ matrix.ansible-core-version }}" ansible-lint yamllint | |
| ansible-galaxy collection install -r requirements.yml | |
| - name: Ansible Syntax Check | |
| run: ansible-playbook site.yml --syntax-check | |
| - name: YAML Lint | |
| run: yamllint . | |
| - name: Ansible Lint | |
| run: ansible-lint . | |
| - name: Role Linting | |
| run: | | |
| for role in roles/*/; do | |
| echo "Linting $role" | |
| ansible-lint "$role" || echo "Linting failed for $role" | |
| done | |
| # Security scanning job for vulnerabilities and secrets | |
| security: | |
| name: Security Scanning | |
| runs-on: ubuntu-latest | |
| needs: changes | |
| if: needs.changes.outputs.any == 'true' || needs.changes.outputs.workflow == 'true' | |
| strategy: | |
| matrix: | |
| python-version: [3.9] | |
| steps: | |
| - name: Checkout Code | |
| uses: actions/checkout@v4 | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Cache Python Dependencies | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.cache/pip | |
| key: ${{ runner.os }}-pip-security-${{ matrix.python-version }}-${{ hashFiles('**/requirements.yml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pip-security-${{ matrix.python-version }}- | |
| - name: Install Security Tools | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install "ansible-core==2.15" bandit safety | |
| - name: Secret Detection with GitLeaks | |
| uses: gitleaks/gitleaks-action@v2 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Dependency Vulnerability Scanning | |
| run: | | |
| # Check for known vulnerabilities in Python dependencies | |
| safety check || echo "Safety check completed with findings" | |
| - name: Ansible Security Analysis | |
| run: | | |
| # Check for common security issues in Ansible playbooks | |
| ansible-playbook site.yml --check --diff -e "ansible_check_mode=true" | |
| - name: Configuration Security Validation | |
| run: | | |
| # Validate that security configurations are properly set | |
| echo "Checking for security best practices..." | |
| # Add specific security checks here based on project requirements | |
| # Molecule testing job for role-level testing | |
| molecule: | |
| name: Molecule Testing | |
| runs-on: ubuntu-latest | |
| needs: [changes, lint] | |
| if: needs.changes.outputs.roles == 'true' || needs.changes.outputs.molecule == 'true' || needs.changes.outputs.workflow == 'true' | |
| strategy: | |
| matrix: | |
| python-version: [3.8, 3.9, 3.10, 3.11] | |
| ansible-core-version: ["2.12", "2.13", "2.14", "2.15"] | |
| scenario: [default, docker, rust, common] | |
| include: | |
| # Include specific combinations for comprehensive testing | |
| - python-version: 3.11 | |
| ansible-core-version: "2.15" | |
| scenario: default | |
| - python-version: 3.8 | |
| ansible-core-version: "2.12" | |
| scenario: default | |
| steps: | |
| - name: Checkout Code | |
| uses: actions/checkout@v4 | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Cache Python Dependencies | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.cache/pip | |
| key: ${{ runner.os }}-pip-molecule-${{ matrix.python-version }}-${{ matrix.ansible-core-version }}-${{ hashFiles('**/requirements.yml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pip-molecule-${{ matrix.python-version }}-${{ matrix.ansible-core-version }}- | |
| - name: Install Dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install "ansible-core==${{ matrix.ansible-core-version }}" molecule[docker] pytest | |
| ansible-galaxy collection install -r requirements.yml | |
| - name: Cache Docker Images | |
| uses: actions/cache@v4 | |
| with: | |
| path: /tmp/docker-images | |
| key: ${{ runner.os }}-docker-images-${{ matrix.scenario }} | |
| restore-keys: | | |
| ${{ runner.os }}-docker-images- | |
| - name: Run Molecule Tests | |
| run: | | |
| cd molecule/${{ matrix.scenario }} | |
| molecule test | |
| env: | |
| PY_COLORS: "1" | |
| ANSIBLE_FORCE_COLOR: "1" | |
| - name: Upload Test Results | |
| uses: actions/upload-artifact@v4 | |
| if: always() | |
| with: | |
| name: molecule-test-results-${{ matrix.python-version }}-${{ matrix.ansible-core-version }}-${{ matrix.scenario }} | |
| path: | | |
| reports/ | |
| logs/ | |
| coverage.xml | |
| if-no-files-found: ignore | |
| # Integration testing job for full playbook testing | |
| integration: | |
| name: Integration Testing | |
| runs-on: ubuntu-latest | |
| needs: [changes, lint] | |
| if: needs.changes.outputs.any == 'true' || needs.changes.outputs.workflow == 'true' | |
| strategy: | |
| matrix: | |
| python-version: [3.9, 3.10, 3.11] | |
| ansible-core-version: ["2.14", "2.15"] | |
| ubuntu-version: ["20.04", "22.04", "24.04"] | |
| include: | |
| # Include specific combinations for comprehensive testing | |
| - python-version: 3.11 | |
| ansible-core-version: "2.15" | |
| ubuntu-version: "22.04" | |
| - python-version: 3.9 | |
| ansible-core-version: "2.13" | |
| ubuntu-version: "20.04" | |
| steps: | |
| - name: Checkout Code | |
| uses: actions/checkout@v4 | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Cache Python Dependencies | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.cache/pip | |
| key: ${{ runner.os }}-pip-integration-${{ matrix.python-version }}-${{ matrix.ansible-core-version }}-${{ hashFiles('**/requirements.yml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pip-integration-${{ matrix.python-version }}-${{ matrix.ansible-core-version }}- | |
| - name: Install Dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install "ansible-core==${{ matrix.ansible-core-version }}" | |
| ansible-galaxy collection install -r requirements.yml | |
| - name: Create Test Inventory Directory | |
| run: | | |
| mkdir -p inventory/test | |
| cat > inventory/test.ini << EOF | |
| [test] | |
| localhost ansible_connection=local | |
| EOF | |
| - name: Create Test Vault Directory | |
| run: | | |
| mkdir -p group_vars/all | |
| cat > group_vars/all/test-vault.yml << EOF | |
| # Test vault values for CI | |
| tailscale_auth_key: "test-key" | |
| atuin_user: "test-user" | |
| atuin_pass: "test-pass" | |
| atuin_key: "test-key" | |
| EOF | |
| - name: Run Integration Tests | |
| run: | | |
| ansible-playbook -i inventory/test.ini test-docker.yml --check --diff | |
| ansible-playbook -i inventory/test.ini test-rust.yml --check --diff | |
| ansible-playbook -i inventory/test.ini test-atuin.yml --check --diff | |
| - name: Run Full Playbook in Check Mode | |
| run: | | |
| ansible-playbook -i inventory/test.ini site.yml --check --diff | |
| - name: Upload Integration Test Results | |
| uses: actions/upload-artifact@v4 | |
| if: always() | |
| with: | |
| name: integration-test-results-${{ matrix.python-version }}-${{ matrix.ansible-core-version }}-ubuntu${{ matrix.ubuntu-version }} | |
| path: | | |
| reports/ | |
| logs/ | |
| coverage.xml | |
| if-no-files-found: ignore | |
| # Performance testing job for benchmarking critical operations | |
| performance: | |
| name: Performance Testing | |
| runs-on: ubuntu-latest | |
| needs: [changes, lint] | |
| if: needs.changes.outputs.any == 'true' || needs.changes.outputs.workflow == 'true' | |
| strategy: | |
| matrix: | |
| python-version: [3.9, 3.11] | |
| ansible-core-version: ["2.15"] | |
| steps: | |
| - name: Checkout Code | |
| uses: actions/checkout@v4 | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Cache Python Dependencies | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.cache/pip | |
| key: ${{ runner.os }}-pip-performance-${{ matrix.python-version }}-${{ matrix.ansible-core-version }}-${{ hashFiles('**/requirements.yml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pip-performance-${{ matrix.python-version }}-${{ matrix.ansible-core-version }}- | |
| - name: Install Dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install "ansible-core==${{ matrix.ansible-core-version }}" | |
| ansible-galaxy collection install -r requirements.yml | |
| - name: Performance Benchmark | |
| run: | | |
| echo "Running performance tests..." | |
| # Add performance testing commands here | |
| # This could include timing ansible runs, measuring resource usage, etc. | |
| - name: Upload Performance Results | |
| uses: actions/upload-artifact@v4 | |
| if: always() | |
| with: | |
| name: performance-results-${{ matrix.python-version }}-${{ matrix.ansible-core-version }} | |
| path: | | |
| performance-reports/ | |
| benchmarks/ | |
| if-no-files-found: ignore | |
| # Deployment validation job for different environments | |
| deployment: | |
| name: Deployment Validation | |
| runs-on: ubuntu-latest | |
| needs: [changes, lint] | |
| if: needs.changes.outputs.any == 'true' || needs.changes.outputs.workflow == 'true' | |
| strategy: | |
| matrix: | |
| environment: [development, staging, production] | |
| python-version: [3.9, 3.11] | |
| ansible-core-version: ["2.14", "2.15"] | |
| steps: | |
| - name: Checkout Code | |
| uses: actions/checkout@v4 | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Cache Python Dependencies | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.cache/pip | |
| key: ${{ runner.os }}-pip-deployment-${{ matrix.python-version }}-${{ matrix.ansible-core-version }}-${{ matrix.environment }}-${{ hashFiles('**/requirements.yml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pip-deployment-${{ matrix.python-version }}-${{ matrix.ansible-core-version }}-${{ matrix.environment }}- | |
| - name: Install Dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install "ansible-core==${{ matrix.ansible-core-version }}" | |
| ansible-galaxy collection install -r requirements.yml | |
| - name: Validate Environment Configuration | |
| run: | | |
| echo "Validating configuration for ${{ matrix.environment }} environment" | |
| # Add environment-specific validation here | |
| - name: Run Environment-Specific Tests | |
| run: | | |
| echo "Running tests for ${{ matrix.environment }} environment" | |
| # Add environment-specific tests here | |
| # Job to collect and report test results | |
| report: | |
| name: Test Results & Reporting | |
| runs-on: ubuntu-latest | |
| needs: [lint, security, molecule, integration, performance, deployment] | |
| if: always() | |
| steps: | |
| - name: Checkout Code | |
| uses: actions/checkout@v4 | |
| - name: Download All Artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: artifacts/ | |
| - name: Create Test Summary | |
| run: | | |
| echo "## CI/CD Pipeline Results" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "| Job | Status |" >> $GITHUB_STEP_SUMMARY | |
| echo "|-----|--------|" >> $GITHUB_STEP_SUMMARY | |
| echo "| Linting | ${{ needs.lint.result }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Security | ${{ needs.security.result }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Molecule | ${{ needs.molecule.result }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Integration | ${{ needs.integration.result }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Performance | ${{ needs.performance.result }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Deployment | ${{ needs.deployment.result }} |" >> $GITHUB_STEP_SUMMARY | |
| - name: Quality Gate Check | |
| run: | | |
| # Check if all required jobs passed | |
| if [[ "${{ needs.lint.result }}" == "success" && "${{ needs.security.result }}" == "success" ]]; then | |
| echo "Quality gates passed" | |
| else | |
| echo "Quality gates failed" | |
| exit 1 | |
| fi | |
| - name: Notify on Failure | |
| if: failure() | |
| run: | | |
| echo "Pipeline failed! Notifying team..." | |
| # Add notification logic here (Slack, email, etc.) | |
| - name: Notify on Success | |
| if: success() | |
| run: | | |
| echo "Pipeline succeeded! All tests passed." | |
| # Add success notification logic here if needed | |
| - name: Generate Coverage Report | |
| run: | | |
| echo "Generating coverage report..." | |
| # Add coverage report generation logic here | |
| - name: Comment on Pull Request | |
| if: github.event_name == 'pull_request' | |
| uses: actions/github-script@v7 | |
| with: | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| script: | | |
| const fs = require('fs'); | |
| const summary = `## CI/CD Pipeline Results\n\n| Job | Status |\n|-----|--------|\n| Linting | ${{ needs.lint.result }} |\n| Security | ${{ needs.security.result }} |\n| Molecule | ${{ needs.molecule.result }} |\n| Integration | ${{ needs.integration.result }} |\n| Performance | ${{ needs.performance.result }} |\n| Deployment | ${{ needs.deployment.result }} |`; | |
| github.rest.issues.createComment({ | |
| issue_number: context.issue.number, | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| body: summary | |
| }); | |
| - name: Create Issue on Failure | |
| if: failure() && github.ref == 'refs/heads/main' | |
| uses: actions/github-script@v7 | |
| with: | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| script: | | |
| github.rest.issues.create({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| title: `CI/CD Pipeline Failure on ${context.ref}`, | |
| body: `The CI/CD pipeline failed on ${context.ref}.\n\nCheck the workflow run: ${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}` | |
| }); | |
| # Conditional execution based on changed files | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true |