continuous-integration #6568
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
| # This workflow executes the following actions: | |
| # - Runs Golang and ShellCheck linters | |
| # - Runs Unit tests | |
| # - Verifies API doc and CRDs are up to date | |
| # - Builds the operator image (no push) | |
| name: continuous-integration | |
| on: | |
| push: | |
| branches: | |
| - main | |
| - release-* | |
| pull_request: | |
| workflow_dispatch: | |
| schedule: | |
| - cron: '0 1 * * *' | |
| permissions: read-all | |
| # set up environment variables to be used across all the jobs | |
| env: | |
| # renovate: datasource=github-releases depName=golangci/golangci-lint versioning=loose | |
| GOLANGCI_LINT_VERSION: "v2.11.4" | |
| KUBEBUILDER_VERSION: "2.3.1" | |
| # renovate: datasource=github-tags depName=kubernetes-sigs/kind versioning=semver | |
| KIND_VERSION: "v0.31.0" | |
| OPERATOR_IMAGE_NAME: "ghcr.io/${{ github.repository }}-testing" | |
| API_DOC_NAME: "cloudnative-pg.v1.md" | |
| SLACK_USERNAME: "cnpg-bot" | |
| # Keep in mind that adding more platforms (architectures) will increase the building | |
| # time even if we use the ghcache for the building process. | |
| PLATFORMS: "linux/amd64,linux/arm64" | |
| BUILD_PUSH_PROVENANCE: "" | |
| BUILD_PUSH_CACHE_FROM: "" | |
| BUILD_PUSH_CACHE_TO: "" | |
| BUILD_PLUGIN_RELEASE_ARGS: "build --skip=validate --clean --id kubectl-cnpg --timeout 60m" | |
| BUILD_MANAGER_RELEASE_ARGS: "build --skip=validate --clean --id manager-race" | |
| REPOSITORY_OWNER: "cloudnative-pg" | |
| REGISTRY: "ghcr.io" | |
| REGISTRY_USER: ${{ github.actor }} | |
| REGISTRY_PASSWORD: ${{ secrets.GITHUB_TOKEN }} | |
| SIGN_IMAGES: "true" | |
| # renovate: datasource=git-refs depName=https://github.com/redhat-openshift-ecosystem/community-operators-pipeline.git versioning=git currentValue=ci/latest | |
| OPP_SCRIPT_VERSION: "fbac22ff0c713188bdcea36791b70fb3999e6e03" | |
| defaults: | |
| run: | |
| # default failure handling for shell scripts in 'run' steps | |
| shell: 'bash -Eeuo pipefail -x {0}' | |
| jobs: | |
| # Trigger the workflow on release-* branches for smoke testing whenever it's a scheduled run. | |
| # Note: this is a workaround since we can't directly schedule-run a workflow from a non default branch | |
| smoke_test_release_branches: | |
| runs-on: ubuntu-24.04 | |
| permissions: | |
| actions: write | |
| name: smoke test release-* branches when it's a scheduled run | |
| if: github.event_name == 'schedule' | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| branch: [release-1.25, release-1.28, release-1.29] | |
| env: | |
| BRANCH: ${{ matrix.branch }} | |
| steps: | |
| - name: Invoke workflow with inputs | |
| uses: benc-uk/workflow-dispatch@7a027648b88c2413826b6ddd6c76114894dc5ec4 # v1 | |
| with: | |
| workflow: continuous-integration | |
| ref: ${{ env.BRANCH }} | |
| # Detects if we should skip the workflow due to being duplicated. Exceptions: | |
| # 1. it's on 'main' branch | |
| # 2. it's triggered by events in the 'do_not_skip' list | |
| duplicate_runs: | |
| runs-on: ubuntu-24.04 | |
| name: Skip duplicate runs | |
| continue-on-error: true | |
| outputs: | |
| should_skip: ${{ steps.skip_check.outputs.should_skip == 'true' && github.ref != 'refs/heads/main' }} | |
| steps: | |
| - id: skip_check | |
| uses: fkirc/skip-duplicate-actions@f75f66ce1886f00957d99748a42c724f4330bdcf # v5.3.1 | |
| with: | |
| concurrent_skipping: 'same_content' | |
| skip_after_successful_duplicate: 'true' | |
| paths_ignore: '["README.md", "docs/**"]' | |
| do_not_skip: '["pull_request", "workflow_dispatch", "schedule"]' | |
| # Classify codebase changes along 5 different dimensions based on the files | |
| # changed in the commit/PR, and create 5 different filters which are used in | |
| # the following jobs to decide whether the step should be skipped. | |
| change-triage: | |
| name: Check changed files | |
| needs: duplicate_runs | |
| if: ${{ needs.duplicate_runs.outputs.should_skip != 'true' }} | |
| runs-on: ubuntu-24.04 | |
| outputs: | |
| docs-changed: ${{ steps.filter.outputs.docs-changed }} | |
| operator-changed: ${{ steps.filter.outputs.operator-changed }} | |
| test-changed: ${{ steps.filter.outputs.test-changed }} | |
| shell-script-changed: ${{ steps.filter.outputs.shell-script-changed }} | |
| go-code-changed: ${{ steps.filter.outputs.go-code-changed }} | |
| renovate-changed: ${{ steps.filter.outputs.renovate-changed }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| - name: Check for changes | |
| uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1 | |
| id: filter | |
| # Remember to add new folders in the operator-changed filter if needed | |
| with: | |
| base: ${{ (github.event_name == 'schedule') && 'main' || '' }} | |
| filters: | | |
| docs-changed: | |
| - '**/*.md' | |
| - 'docs/**' | |
| - '.wordlist-en-custom.txt' | |
| operator-changed: | |
| - 'api/**' | |
| - 'cmd/**' | |
| - 'config/**' | |
| - 'internal/**' | |
| - 'licenses/**' | |
| - 'pkg/**' | |
| - '.github/workflows/continuous-delivery.yml' | |
| - '.github/workflows/continuous-integration.yml' | |
| - '.goreleaser*.yml' | |
| - 'Dockerfile' | |
| - 'docker-bake.hcl' | |
| - 'Makefile' | |
| - 'go.mod' | |
| - 'go.sum' | |
| test-changed: | |
| - '.github/e2e-matrix-generator.py' | |
| - '.github/generate-test-artifacts.py' | |
| - 'tests/**' | |
| - 'hack/**' | |
| shell-script-changed: | |
| - '**/*.sh' | |
| go-code-changed: | |
| - '**/*.go' | |
| - '.golangci.yml' | |
| renovate-changed: | |
| - '.github/renovate.json5' | |
| go-linters: | |
| name: Run linters | |
| needs: | |
| - duplicate_runs | |
| - change-triage | |
| # We need always run linter as go linter is a required check | |
| if: needs.duplicate_runs.outputs.should_skip != 'true' | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| - name: Install Go | |
| uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 | |
| with: | |
| # Disable setup-go caching. Cache is better handled by the golangci-lint action | |
| cache: false | |
| go-version-file: go.mod | |
| check-latest: true | |
| - name: Run golangci-lint | |
| uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9 | |
| with: | |
| version: ${{ env.GOLANGCI_LINT_VERSION }} | |
| - name: Check go mod tidy has no pending changes | |
| run: | | |
| make go-mod-check | |
| renovate-linter: | |
| name: Renovate Linter | |
| needs: | |
| - duplicate_runs | |
| - change-triage | |
| if: | | |
| needs.duplicate_runs.outputs.should_skip != 'true' && | |
| needs.change-triage.outputs.renovate-changed == 'true' | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| - name: Validate Renovate JSON | |
| run: npx --yes --package renovate@latest -- renovate-config-validator | |
| go-vulncheck: | |
| name: Run govulncheck | |
| needs: | |
| - duplicate_runs | |
| - change-triage | |
| if: | | |
| needs.duplicate_runs.outputs.should_skip != 'true' && | |
| ( | |
| needs.change-triage.outputs.operator-changed == 'true' || | |
| needs.change-triage.outputs.go-code-changed == 'true' | |
| ) | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - name: Run govulncheck | |
| uses: golang/govulncheck-action@b625fbe08f3bccbe446d94fbf87fcc875a4f50ee # v1 | |
| with: | |
| go-version-file: go.mod | |
| # Override the default value of "stable" for go-version-input. | |
| # Without this, setup-go receives both go-version=stable and | |
| # go-version-file=go.mod, and ignores the file. | |
| # See https://github.com/golang/go/issues/70036 | |
| go-version-input: "" | |
| check-latest: true | |
| shellcheck: | |
| name: Run shellcheck linter | |
| needs: | |
| - duplicate_runs | |
| - change-triage | |
| # Run shellcheck linter only if shell code has changed | |
| if: | | |
| needs.duplicate_runs.outputs.should_skip != 'true' && | |
| needs.change-triage.outputs.shell-script-changed == 'true' | |
| runs-on: ubuntu-24.04 | |
| env: | |
| SHELLCHECK_OPTS: -a -x -S style | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| - name: Run ShellCheck | |
| uses: ludeeus/action-shellcheck@00cae500b08a931fb5698e11e79bfbd38e612a38 # 2.0.0 | |
| generate-unit-tests-jobs: | |
| name: Generate jobs for unit tests | |
| needs: | |
| - duplicate_runs | |
| - change-triage | |
| # Generate unit tests jobs only if the operator or the Go codebase have changed | |
| if: | | |
| needs.duplicate_runs.outputs.should_skip != 'true' && | |
| ( | |
| needs.change-triage.outputs.operator-changed == 'true' || | |
| needs.change-triage.outputs.go-code-changed == 'true' | |
| ) | |
| runs-on: ubuntu-24.04 | |
| outputs: | |
| k8sMatrix: ${{ steps.get-k8s-versions.outputs.k8s_versions }} | |
| latest_k8s_version: ${{ steps.get-k8s-versions.outputs.latest_k8s_version }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| - name: Get k8s versions for unit test | |
| id: get-k8s-versions | |
| shell: bash | |
| run: | | |
| k8s_versions=$(jq -c ' | |
| .unit_test.max as $max | | |
| .unit_test.min as $min | | |
| $min | [ while(. <= $max; | |
| . | split(".") | .[1] |= (.|tonumber|.+1|tostring) | join(".") | |
| ) | |
| ] | | |
| .[] |= .+".x" | |
| ' < .github/k8s_versions_scope.json) | |
| echo "k8s_versions=${k8s_versions}" >> $GITHUB_OUTPUT | |
| latest_k8s_version=$(jq -r '.|last' <<< $k8s_versions) | |
| echo "latest_k8s_version=${latest_k8s_version}" >> $GITHUB_OUTPUT | |
| tests: | |
| name: Run unit tests | |
| needs: | |
| - duplicate_runs | |
| - change-triage | |
| - generate-unit-tests-jobs | |
| # Run unit tests only if the operator or the Go codebase have changed | |
| if: | | |
| needs.duplicate_runs.outputs.should_skip != 'true' && | |
| ( | |
| needs.change-triage.outputs.operator-changed == 'true' || | |
| needs.change-triage.outputs.go-code-changed == 'true' | |
| ) | |
| runs-on: ubuntu-24.04 | |
| strategy: | |
| matrix: | |
| # The Unit test is performed per multiple supported k8s versions (each job for each k8s version) as below: | |
| k8s-version: ${{ fromJSON(needs.generate-unit-tests-jobs.outputs.k8sMatrix) }} | |
| env: | |
| ENVTEST_K8S_VERSION: ${{ matrix.k8s-version }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| - name: Install Go | |
| uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 | |
| with: | |
| go-version-file: go.mod | |
| check-latest: true | |
| - name: Run unit tests | |
| run: | | |
| make test | |
| - name: Coverage Summary | |
| if: env.ENVTEST_K8S_VERSION == needs.generate-unit-tests-jobs.outputs.latest_k8s_version | |
| run: | | |
| go tool cover -func=cover.out -o coverage.out | |
| - name: Publish unit test summary on the latest k8s version | |
| if: env.ENVTEST_K8S_VERSION == needs.generate-unit-tests-jobs.outputs.latest_k8s_version | |
| run: | | |
| echo "Unit test coverage: $(tail -n 1 coverage.out | awk '{print $3}')" >> $GITHUB_STEP_SUMMARY | |
| apidoc: | |
| name: Verify API doc is up to date | |
| needs: | |
| - duplicate_runs | |
| - change-triage | |
| # Run make apidoc if Go code or docs have changed | |
| if: | | |
| needs.duplicate_runs.outputs.should_skip != 'true' && | |
| ( | |
| needs.change-triage.outputs.go-code-changed == 'true' || | |
| needs.change-triage.outputs.docs-changed == 'true' | |
| ) | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| - name: Install Go | |
| uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 | |
| with: | |
| go-version-file: go.mod | |
| check-latest: true | |
| - name: Run make apidoc | |
| run: | | |
| make apidoc | |
| - name: Verify apidoc changes | |
| run: | | |
| apidoc_file_path='docs/src/${{ env.API_DOC_NAME }}' | |
| if git status --porcelain $apidoc_file_path | grep '^ M'; then | |
| echo "The API documentation doesn't reflect the current API. Please run make apidoc." | |
| exit 1 | |
| fi | |
| docs-build: | |
| name: Verify documentation builds | |
| needs: | |
| - duplicate_runs | |
| - change-triage | |
| if: | | |
| needs.duplicate_runs.outputs.should_skip != 'true' && | |
| needs.change-triage.outputs.docs-changed == 'true' | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| - name: Build documentation | |
| run: | | |
| docker run --rm \ | |
| -v ./docs/src:/website/docs \ | |
| ghcr.io/cloudnative-pg/docs:latest \ | |
| yarn build | |
| crd: | |
| name: Verify CRD is up to date | |
| needs: | |
| - duplicate_runs | |
| - change-triage | |
| # Run make manifests if Go code have changed | |
| if: | | |
| needs.duplicate_runs.outputs.should_skip != 'true' && | |
| ( | |
| needs.change-triage.outputs.go-code-changed == 'true' || | |
| needs.change-triage.outputs.operator-changed == 'true' | |
| ) | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| - name: Install Go | |
| uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 | |
| with: | |
| go-version-file: go.mod | |
| check-latest: true | |
| - name: Run make manifests | |
| run: | | |
| make manifests | |
| - name: Check CRD manifests are up to date | |
| run: | | |
| crd_path='config/crd' | |
| if git status --porcelain $crd_path | grep '^ M'; then | |
| echo "The CRD manifests do not reflect the current API. Please run make manifests." | |
| exit 1 | |
| fi | |
| buildx: | |
| name: Build containers | |
| needs: | |
| - go-linters | |
| - shellcheck | |
| - tests | |
| - apidoc | |
| - crd | |
| - duplicate_runs | |
| - change-triage | |
| # Build containers: | |
| # if there have been any code changes OR it is a scheduled execution | |
| # AND | |
| # none of the preceding jobs failed | |
| if: | | |
| (always() && !cancelled()) && | |
| ( | |
| needs.duplicate_runs.outputs.should_skip != 'true' && | |
| ( | |
| needs.change-triage.outputs.operator-changed == 'true' || | |
| needs.change-triage.outputs.test-changed == 'true' || | |
| needs.change-triage.outputs.shell-script-changed == 'true' || | |
| needs.change-triage.outputs.go-code-changed == 'true' | |
| ) | |
| ) && | |
| (needs.go-linters.result == 'success' || needs.go-linters.result == 'skipped') && | |
| (needs.shellcheck.result == 'success' || needs.shellcheck.result == 'skipped') && | |
| (needs.tests.result == 'success' || needs.tests.result == 'skipped') && | |
| (needs.apidoc.result == 'success' || needs.apidoc.result == 'skipped') && | |
| (needs.crd.result == 'success' || needs.crd.result == 'skipped') | |
| runs-on: ${{ github.repository_owner == 'cloudnative-pg' && 'ubuntu-latest-16-cores' || 'ubuntu-24.04' }} | |
| permissions: | |
| actions: read | |
| contents: read | |
| packages: write | |
| security-events: write | |
| id-token: write | |
| outputs: | |
| commit_version: ${{ env.VERSION }} | |
| commit: ${{ env.COMMIT_SHA }} | |
| controller_img: ${{ env.CONTROLLER_IMG }} | |
| controller_img_ubi: ${{ env.CONTROLLER_IMG_UBI }} | |
| bundle_img: ${{ env.BUNDLE_IMG }} | |
| catalog_img: ${{ env.CATALOG_IMG }} | |
| push: ${{ env.PUSH }} | |
| images_matrix: ${{ steps.images_matrix.outputs.images_matrix }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| # To identify the commit we need the history and all the tags. | |
| fetch-depth: 0 | |
| - name: Install Go | |
| uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 | |
| with: | |
| go-version-file: go.mod | |
| check-latest: true | |
| - name: Build meta | |
| id: build-meta | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| COMMIT_REF: ${{ github.event.pull_request.head.sha || github.sha }} | |
| EVENT_NAME: ${{ github.event_name }} | |
| PR_NUMBER: ${{ github.event.pull_request.number }} | |
| run: | | |
| commit_sha="${COMMIT_REF}" | |
| commit_date=$(git log -1 --pretty=format:'%ad' --date short "${commit_sha}" || : ) | |
| # use git describe to get the nearest tag and use that to build the version (e.g. 1.4.0-dev24 or 1.4.0) | |
| commit_version=$(git describe --tags --match 'v*' "${commit_sha}"| sed -e 's/^v//; s/-g[0-9a-f]\+$//; s/-\([0-9]\+\)$/-dev\1/') | |
| # shortened commit sha | |
| commit_short=$(git rev-parse --short "${commit_sha}") | |
| # extract branch name | |
| branch_name=${GITHUB_REF#refs/heads/} | |
| if [[ "${EVENT_NAME}" == 'pull_request' ]] | |
| then | |
| branch_name=$(gh pr view "${PR_NUMBER}" --json headRefName -q '.headRefName' 2>/dev/null) | |
| fi | |
| # extract tag from branch name | |
| tag_name=$(echo "$branch_name" | tr / - | head -c 50) | |
| echo "DATE=${commit_date}" >> $GITHUB_ENV | |
| echo "VERSION=${commit_version}" >> $GITHUB_ENV | |
| echo "COMMIT=${commit_short}" >> $GITHUB_ENV | |
| echo "COMMIT_SHA=${commit_sha}" >> $GITHUB_ENV | |
| echo "IMAGE_TAG=${tag_name,,}" >> $GITHUB_ENV | |
| echo "REPO_OWNER=${GITHUB_REPOSITORY_OWNER,,}" >> $GITHUB_ENV | |
| # By default the container image is being pushed to the registry | |
| echo "PUSH=true" >> $GITHUB_ENV | |
| # GITHUB_TOKEN has restricted permissions if the pull_request has been opened | |
| # from a forked repository, so we avoid pushing to the container registry if | |
| # that's the case. | |
| - name: Evaluate container image push | |
| if: github.event_name == 'pull_request' | |
| env: | |
| BASE_REPO: ${{ github.event.pull_request.base.repo.full_name }} | |
| HEAD_REPO: ${{ github.event.pull_request.head.repo.full_name }} | |
| run: | | |
| if [[ "${HEAD_REPO}" != "${BASE_REPO}" ]] | |
| then | |
| echo "PUSH=false" >> $GITHUB_ENV | |
| fi | |
| - name: Set GoReleaser environment | |
| run: | | |
| echo GOPATH=$(go env GOPATH) >> $GITHUB_ENV | |
| echo PWD=$(pwd) >> $GITHUB_ENV | |
| - name: Run GoReleaser to build kubectl plugin | |
| uses: goreleaser/goreleaser-action@1a80836c5c9d9e5755a25cb59ec6f45a3b5f41a8 # v7 | |
| if: | | |
| github.event_name == 'schedule' || | |
| ( | |
| github.event_name == 'workflow_dispatch' && | |
| startsWith(github.head_ref, 'release-') || | |
| startsWith(github.ref_name, 'release-') | |
| ) | |
| with: | |
| distribution: goreleaser | |
| version: v2 | |
| args: ${{ env.BUILD_PLUGIN_RELEASE_ARGS }} | |
| env: | |
| DATE: ${{ env.DATE }} | |
| COMMIT: ${{ env.COMMIT }} | |
| VERSION: ${{ env.VERSION }} | |
| # Send Slack notification if the kubectl plugin build fails. | |
| # To avoid message overflow, we only report runs scheduled on main or release branches | |
| - name: Slack Notification | |
| uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # v2 | |
| if: | | |
| failure() && | |
| github.repository_owner == env.REPOSITORY_OWNER && | |
| ( | |
| github.event_name == 'schedule' || | |
| ( | |
| github.event_name == 'workflow_dispatch' && | |
| startsWith(github.head_ref, 'release-') || | |
| startsWith(github.ref_name, 'release-') | |
| ) | |
| ) | |
| env: | |
| SLACK_COLOR: ${{ job.status }} | |
| SLACK_ICON: https://avatars.githubusercontent.com/u/85171364?size=48 | |
| SLACK_USERNAME: ${{ env.SLACK_USERNAME }} | |
| SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} | |
| SLACK_MESSAGE: Building kubernetes plugin failed! | |
| - name: Run GoReleaser | |
| uses: goreleaser/goreleaser-action@1a80836c5c9d9e5755a25cb59ec6f45a3b5f41a8 # v7 | |
| with: | |
| distribution: goreleaser | |
| version: v2 | |
| args: ${{ env.BUILD_MANAGER_RELEASE_ARGS }} | |
| env: | |
| DATE: ${{ env.DATE }} | |
| COMMIT: ${{ env.COMMIT }} | |
| VERSION: ${{ env.VERSION }} | |
| RACE: "true" | |
| - name: Set up QEMU | |
| uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4 | |
| with: | |
| platforms: ${{ env.PLATFORMS }} | |
| cache-image: false | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4 | |
| - name: Login into docker registry | |
| uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ env.REGISTRY_USER }} | |
| password: ${{ env.REGISTRY_PASSWORD }} | |
| - name: Build and push | |
| uses: docker/bake-action@a66e1c87e2eca0503c343edf1d208c716d54b8a8 # v7 | |
| id: bake-push | |
| env: | |
| BUILDX_METADATA_PROVENANCE: disabled | |
| environment: "testing" | |
| buildVersion: ${{ env.VERSION }} | |
| tag: ${{ env.IMAGE_TAG }} | |
| registry: ${{ env.REGISTRY }}/${{ env.REPO_OWNER }} | |
| revision: ${{ env.COMMIT }} | |
| with: | |
| source: . | |
| push: ${{ env.PUSH }} | |
| no-cache: true | |
| targets: "default" | |
| - name: Output images | |
| if: env.PUSH == 'true' | |
| env: | |
| DISTROLESS: ${{ fromJSON(steps.bake-push.outputs.metadata)['distroless']['image.name'] }} | |
| UBI: ${{ fromJSON(steps.bake-push.outputs.metadata)['ubi']['image.name'] }} | |
| run: | | |
| echo "CONTROLLER_IMG=${DISTROLESS}" >> $GITHUB_ENV | |
| echo "CONTROLLER_IMG_UBI=${UBI}" >> $GITHUB_ENV | |
| echo "BUNDLE_IMG=${UBI}-bundle" >> $GITHUB_ENV | |
| echo "CATALOG_IMG=${UBI}-catalog" >> $GITHUB_ENV | |
| - name: Dockle scan distroless image | |
| uses: erzz/dockle-action@e8a7c41f36f1236ca3282b298d425ffbfdb2e922 # v1 | |
| if: env.PUSH == 'true' | |
| with: | |
| image: ${{ env.CONTROLLER_IMG }} | |
| exit-code: '1' | |
| failure-threshold: WARN | |
| accept-keywords: key | |
| - name: Dockle scan UBI image | |
| uses: erzz/dockle-action@e8a7c41f36f1236ca3282b298d425ffbfdb2e922 # v1 | |
| if: env.PUSH == 'true' | |
| env: | |
| DOCKLE_IGNORES: CIS-DI-0009 | |
| with: | |
| image: ${{ env.CONTROLLER_IMG_UBI }} | |
| exit-code: '1' | |
| failure-threshold: WARN | |
| accept-keywords: key | |
| - name: Run Snyk to check Docker image for vulnerabilities | |
| uses: snyk/actions/docker@9adf32b1121593767fc3c057af55b55db032dc04 # master | |
| if: | | |
| !github.event.repository.fork && | |
| !github.event.pull_request.head.repo.fork | |
| env: | |
| SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} | |
| with: | |
| image: ${{ env.CONTROLLER_IMG }} | |
| args: --severity-threshold=high --file=Dockerfile --username=${{ env.REGISTRY_USER }} --password=${{ env.REGISTRY_PASSWORD }} | |
| - name: Install cosign | |
| if: | | |
| env.SIGN_IMAGES == 'true' && | |
| env.PUSH == 'true' | |
| uses: sigstore/cosign-installer@cad07c2e89fa2edd6e2d7bab4c1aa38e53f76003 # v4.1.1 | |
| # See https://github.blog/security/supply-chain-security/safeguard-container-signing-capability-actions/ | |
| # and https://github.com/actions/starter-workflows/blob/main/ci/docker-publish.yml for more details on | |
| # how to use cosign. | |
| - name: Sign images | |
| if: | | |
| env.SIGN_IMAGES == 'true' && | |
| env.PUSH == 'true' | |
| env: | |
| BAKE_METADATA: ${{ steps.bake-push.outputs.metadata }} | |
| run: | | |
| images=$(echo "${BAKE_METADATA}" | | |
| jq -r '.[] | (."image.name" | sub(",.*";"" )) + "@" + ."containerimage.digest"' | |
| ) | |
| cosign sign --yes ${images} | |
| - name: Prepare images matrix | |
| if: env.PUSH == 'true' | |
| id: images_matrix | |
| env: | |
| BAKE_METADATA: ${{ steps.bake-push.outputs.metadata }} | |
| shell: bash | |
| run: | | |
| images_matrix=$(echo "$BAKE_METADATA" | | |
| jq -r -c ' | |
| del(.[].["containerimage.descriptor", "buildx.build.ref"]) | |
| | to_entries | |
| | map({variant: .key} + .value + {"image.name": (.value["image.name"] | split(",")[0] | sub(":[^/]+$"; ""))}) | |
| ' | |
| ) | |
| echo "images_matrix=${images_matrix}" >> "$GITHUB_OUTPUT" | |
| provenance: | |
| name: Provenance for images | |
| if: | | |
| (always() && !cancelled()) && | |
| needs.buildx.result == 'success' && | |
| needs.buildx.outputs.push == 'true' | |
| needs: | |
| - buildx | |
| permissions: | |
| actions: read | |
| id-token: write | |
| packages: write | |
| strategy: | |
| matrix: | |
| include: ${{ fromJson(needs.buildx.outputs.images_matrix) }} | |
| # NOTE: pinned by tag, not SHA — the SLSA generator's builder-fetch.sh | |
| # resolves the binary download URL from the git ref and breaks with SHA pins. | |
| # See: https://github.com/slsa-framework/slsa-github-generator/issues/4216 | |
| uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v2.1.0 | |
| with: | |
| image: ${{ matrix['image.name'] }} | |
| digest: ${{ matrix['containerimage.digest'] }} | |
| registry-username: ${{ github.actor }} | |
| secrets: | |
| registry-password: ${{ secrets.GITHUB_TOKEN }} | |
| olm-bundle: | |
| name: Create OLM bundle and catalog | |
| runs-on: ubuntu-24.04 | |
| permissions: | |
| contents: read | |
| packages: write | |
| needs: | |
| - buildx | |
| if: | | |
| (always() && !cancelled()) && | |
| needs.buildx.result == 'success' && | |
| needs.buildx.outputs.push == 'true' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| fetch-depth: 0 | |
| ref: ${{ needs.buildx.outputs.commit }} | |
| - name: Set up QEMU | |
| uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4 | |
| with: | |
| platforms: ${{ env.PLATFORMS }} | |
| cache-image: false | |
| - name: Install Go | |
| uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 | |
| with: | |
| go-version-file: go.mod | |
| check-latest: true | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4 | |
| - name: Login into docker registry | |
| uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ env.REGISTRY_USER }} | |
| password: ${{ env.REGISTRY_PASSWORD }} | |
| - name: Create bundle | |
| env: | |
| CONTROLLER_IMG: ${{ needs.buildx.outputs.controller_img_ubi }} | |
| BUNDLE_IMG: ${{ needs.buildx.outputs.bundle_img }} | |
| CATALOG_IMG: ${{ needs.buildx.outputs.catalog_img }} | |
| run: | | |
| make olm-catalog | |
| - name: Archive the bundle manifests | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 | |
| with: | |
| name: bundle | |
| path: | | |
| bundle.Dockerfile | |
| bundle/ | |
| cloudnative-pg-catalog.yaml | |
| retention-days: 7 | |
| preflight: | |
| name: Run openshift-preflight test | |
| runs-on: ubuntu-24.04 | |
| needs: | |
| - buildx | |
| - olm-bundle | |
| if: | | |
| (always() && !cancelled()) && | |
| needs.olm-bundle.result == 'success' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| - name: Install Go | |
| uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 | |
| with: | |
| go-version-file: go.mod | |
| check-latest: true | |
| - name: Setup tools | |
| run: | | |
| make operator-sdk preflight | |
| - name: Loging to container registry | |
| uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ env.REGISTRY_USER }} | |
| password: ${{ env.REGISTRY_PASSWORD }} | |
| - name: Run preflight container test | |
| env: | |
| CONTROLLER_IMG: ${{ needs.buildx.outputs.controller_img_ubi }} | |
| PFLT_ARTIFACTS: "preflight_results" | |
| run: | | |
| bin/preflight check container ${CONTROLLER_IMG} \ | |
| --docker-config $HOME/.docker/config.json | |
| - name: Archive the preflight results | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 | |
| with: | |
| name: preflight_results | |
| path: | | |
| preflight_results | |
| retention-days: 7 | |
| - name: Check preflight container results | |
| run: | | |
| for dir in `ls preflight_results`; do | |
| PASS=`jq -r .passed preflight_results/$dir/results.json` | |
| if [[ "$PASS" == "false" ]] | |
| then | |
| exit 1 | |
| fi | |
| done | |
| olm-scorecard: | |
| name: Run OLM scorecard test | |
| runs-on: ubuntu-24.04 | |
| needs: | |
| - buildx | |
| - olm-bundle | |
| if: | | |
| (always() && !cancelled()) && | |
| needs.olm-bundle.result == 'success' && | |
| github.repository_owner == 'cloudnative-pg' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| - name: Setting up KinD cluster | |
| uses: helm/kind-action@ef37e7f390d99f746eb8b610417061a60e82a6cc # v1.14.0 | |
| with: | |
| wait: "600s" | |
| version: ${{ env.KIND_VERSION }} | |
| - name: Set up QEMU | |
| uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4 | |
| with: | |
| platforms: ${{ env.PLATFORMS }} | |
| cache-image: false | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4 | |
| - name: Login into docker registry | |
| uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ env.REGISTRY_USER }} | |
| password: ${{ env.REGISTRY_PASSWORD }} | |
| - name: Install Go | |
| uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 | |
| with: | |
| go-version-file: go.mod | |
| check-latest: true | |
| - name: Running Scorecard tests | |
| env: | |
| BUNDLE_IMG: ${{ needs.buildx.outputs.bundle_img }} | |
| run: | | |
| make olm-scorecard | |
| olm-tests: | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| test: [ kiwi, lemon, orange ] | |
| name: Run OLM ${{ matrix.test }} test | |
| runs-on: ${{ github.repository_owner == 'cloudnative-pg' && 'ubuntu-latest-16-cores' || 'ubuntu-24.04' }} | |
| needs: | |
| - buildx | |
| - olm-bundle | |
| if: | | |
| (always() && !cancelled()) && | |
| needs.olm-bundle.result == 'success' && | |
| github.repository_owner == 'cloudnative-pg' | |
| env: | |
| VERSION: ${{ needs.buildx.outputs.commit_version }} | |
| OPP_DEBUG: 1 | |
| OPP_PRODUCTION_TYPE: "k8s" | |
| OPP_CONTAINER_OPT: "-t" | |
| OPP_RELEASE_INDEX_NAME: "catalog_tmp" | |
| TEST: ${{ matrix.test }} | |
| steps: | |
| - name: Checkout community-operators | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| repository: k8s-operatorhub/community-operators | |
| persist-credentials: false | |
| - name: Login into docker registry | |
| uses: redhat-actions/podman-login@4934294ad0449894bcd1e9f191899d7292469603 # v1 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ env.REGISTRY_USER }} | |
| password: ${{ env.REGISTRY_PASSWORD }} | |
| - name: Download the bundle | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 | |
| with: | |
| name: bundle | |
| - name: Copy bundle in the community-operators | |
| run: | | |
| mkdir -p "operators/cloudnative-pg/${VERSION}" | |
| cp -R bundle/* "operators/cloudnative-pg/${VERSION}" | |
| rm -fr bundle.Dockerfile *.zip bundle/ | |
| - name: Test bundle | |
| run: | | |
| bash <(curl -sL "https://raw.githubusercontent.com/redhat-openshift-ecosystem/community-operators-pipeline/${OPP_SCRIPT_VERSION}/ci/scripts/opp.sh") "${TEST}" "operators/cloudnative-pg/${VERSION}/" |