CI on "renovate/release-5.5-python-dependencies" by @renovate[bot] #38636
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 | |
| run-name: CI on "${{ github.head_ref && github.head_ref || github.ref }}" by @${{ github.actor }} | |
| on: | |
| pull_request: | |
| branches: | |
| - main | |
| - release-* | |
| merge_group: | |
| workflow_dispatch: | |
| inputs: | |
| force: | |
| type: boolean | |
| description: "Force rebuild" | |
| required: false | |
| default: false | |
| run_tests: | |
| type: boolean | |
| description: "Run unit & e2e tests" | |
| required: false | |
| default: true | |
| defaults: | |
| run: | |
| shell: bash | |
| concurrency: | |
| group: ${{ github.ref_name }}-ci | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| jobs: | |
| checks: | |
| name: Checks and variables | |
| if: github.repository == 'nginx/kubernetes-ingress' | |
| runs-on: ubuntu-24.04 | |
| permissions: | |
| contents: read | |
| id-token: write | |
| outputs: | |
| docs_only: ${{ github.event.pull_request && steps.docs.outputs.docs_only == 'true' }} | |
| k8s_latest: ${{ steps.vars.outputs.k8s_latest }} | |
| go_path: ${{ steps.vars.outputs.go_path }} | |
| go_code_md5: ${{ steps.vars.outputs.go_code_md5 }} | |
| go_proxy: ${{ steps.vars.outputs.go_proxy }} | |
| binary_cache_hit: ${{ steps.binary-cache.outputs.cache-hit }} | |
| chart_version: ${{ steps.vars.outputs.chart_version }} | |
| ic_version: ${{ steps.vars.outputs.ic_version }} | |
| docker_md5: ${{ steps.vars.outputs.docker_md5 }} | |
| build_tag: ${{ steps.vars.outputs.build_tag }} | |
| stable_tag: ${{ steps.vars.outputs.stable_tag }} | |
| forked_workflow: ${{ steps.vars.outputs.forked_workflow }} | |
| stable_image_exists: ${{ steps.stable_exists.outputs.exists }} | |
| additional_tag: ${{ steps.vars.outputs.additional_tag }} | |
| image_matrix_oss: ${{ steps.vars.outputs.image_matrix_oss }} | |
| image_matrix_plus: ${{ steps.vars.outputs.image_matrix_plus }} | |
| image_matrix_nap: ${{ steps.vars.outputs.image_matrix_nap }} | |
| docker_build: ${{ steps.docker_build.outputs.docker_build }} | |
| run_tests: ${{ steps.run_tests.outputs.run_tests }} | |
| steps: | |
| - name: Checkout Repository | |
| uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 | |
| with: | |
| fetch-depth: 0 | |
| - name: Filter only docs changes | |
| id: docs | |
| run: | | |
| ./.github/scripts/variables.sh docs_only >> $GITHUB_OUTPUT | |
| cat $GITHUB_OUTPUT | |
| shell: bash --noprofile --norc -o pipefail {0} | |
| - name: Setup Golang Environment | |
| uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0 | |
| with: | |
| go-version-file: go.mod | |
| - name: Configure pipeline Variables | |
| id: vars | |
| run: | | |
| ./.github/scripts/variables.sh k8s_latest_version >> $GITHUB_OUTPUT | |
| echo "go_path=$(go env GOPATH)" >> $GITHUB_OUTPUT | |
| source .github/data/version.txt | |
| echo "ic_version=${IC_VERSION}" >> $GITHUB_OUTPUT | |
| echo "chart_version=${HELM_CHART_VERSION}" >> $GITHUB_OUTPUT | |
| forked_workflow=${{ (github.event.pull_request && github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name) || github.repository != 'nginx/kubernetes-ingress' }} | |
| echo "forked_workflow=${forked_workflow}" >> $GITHUB_OUTPUT | |
| echo "go_proxy=https://proxy.golang.org,direct" >> $GITHUB_OUTPUT | |
| ./.github/scripts/variables.sh go_code_md5 >> $GITHUB_OUTPUT | |
| ./.github/scripts/variables.sh docker_md5 >> $GITHUB_OUTPUT | |
| ./.github/scripts/variables.sh build_tag >> $GITHUB_OUTPUT | |
| ./.github/scripts/variables.sh stable_tag >> $GITHUB_OUTPUT | |
| REF=${{ github.ref_name }} ./.github/scripts/variables.sh additional_tag >> $GITHUB_OUTPUT | |
| echo "image_matrix_oss=$(cat .github/data/matrix-images-oss.json | jq -c)" >> $GITHUB_OUTPUT | |
| echo "image_matrix_plus=$(cat .github/data/matrix-images-plus.json | jq -c)" >> $GITHUB_OUTPUT | |
| echo "image_matrix_nap=$(cat .github/data/matrix-images-nap.json | jq -c)" >> $GITHUB_OUTPUT | |
| - name: Fetch Cached Binary Artifacts | |
| id: binary-cache | |
| uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5.1.0 | |
| with: | |
| path: ${{ github.workspace }}/dist | |
| key: nginx-ingress-${{ steps.vars.outputs.go_code_md5 }} | |
| lookup-only: true | |
| - name: Azure login | |
| uses: azure/login@532459ea530d8321f2fb9bb10d1e0bcf23869a43 # v3.0.0 | |
| with: | |
| client-id: ${{ secrets.AZURE_VAULT_CLIENT_ID }} | |
| tenant-id: ${{ secrets.AZURE_VAULT_TENANT_ID }} | |
| subscription-id: ${{ secrets.AZURE_VAULT_SUBSCRIPTION_ID }} | |
| if: ${{ steps.vars.outputs.forked_workflow == 'false' }} | |
| - name: Setup secrets | |
| id: secrets | |
| run: | | |
| echo "Setting secrets for job" | |
| GCR_WORKLOAD_ID=$(az keyvault secret show --name gcr-workload-identity --vault-name ${{ secrets.NIC_KEYVAULT_NAME }} --query value -o tsv) | |
| echo "::add-mask::$GCR_WORKLOAD_ID" | |
| echo "GCR_WORKLOAD_ID=$GCR_WORKLOAD_ID" >> $GITHUB_OUTPUT | |
| GCR_SERVICE_ACCOUNT=$(az keyvault secret show --name kic-pipeline-gcr-sa --vault-name ${{ secrets.NIC_KEYVAULT_NAME }} --query value -o tsv) | |
| echo "::add-mask::$GCR_SERVICE_ACCOUNT" | |
| echo "GCR_SERVICE_ACCOUNT=$GCR_SERVICE_ACCOUNT" >> $GITHUB_OUTPUT | |
| if: ${{ steps.vars.outputs.forked_workflow == 'false' }} | |
| - name: Authenticate to Google Cloud | |
| id: auth | |
| uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0 | |
| with: | |
| token_format: access_token | |
| workload_identity_provider: ${{ steps.secrets.outputs.GCR_WORKLOAD_ID }} | |
| service_account: ${{ steps.secrets.outputs.GCR_SERVICE_ACCOUNT }} | |
| if: ${{ steps.vars.outputs.forked_workflow == 'false' }} | |
| - name: Login to GCR | |
| uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0 | |
| with: | |
| registry: gcr.io | |
| username: oauth2accesstoken | |
| password: ${{ steps.auth.outputs.access_token }} | |
| if: ${{ steps.vars.outputs.forked_workflow == 'false' }} | |
| - name: Check if stable image exists | |
| id: stable_exists | |
| run: | | |
| exists=false | |
| if docker pull gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress:${{ steps.vars.outputs.stable_tag }}; then | |
| exists=true | |
| fi | |
| echo "exists=${exists}" >> $GITHUB_OUTPUT | |
| if: ${{ steps.vars.outputs.forked_workflow == 'false' }} | |
| - name: Check if docker build is needed | |
| id: docker_build | |
| run: | | |
| docker_build="false" | |
| if [ "${{ inputs.force }}" = "true" ]; then | |
| docker_build="true" | |
| elif [ "${{ steps.vars.outputs.forked_workflow }}" = "true" ] && [ "${{ steps.docs.outputs.docs_only }}" = "false" ]; then | |
| docker_build="true" | |
| elif [ "${{ steps.vars.outputs.forked_workflow }}" = "false" ] && [ "${{ steps.docs.outputs.docs_only }}" = "false" ] && [ "${{ steps.binary-cache.outputs.cache-hit }}" != "true" ]; then | |
| docker_build="true" | |
| elif [ "${{ steps.vars.outputs.forked_workflow }}" = "false" ] && [ "${{ steps.docs.outputs.docs_only }}" = "false" ] && [ "${{ steps.stable_exists.outputs.exists }}" != "true" ]; then | |
| docker_build="true" | |
| fi | |
| echo "docker_build=${docker_build}" >> $GITHUB_OUTPUT | |
| - name: Check if tests should be run | |
| id: run_tests | |
| run: | | |
| run_tests="true" | |
| if [ "${{ inputs.run_tests }}" = "false" ]; then | |
| run_tests="false" | |
| elif [ "${{ steps.docs.outputs.docs_only }}" = "true" ]; then | |
| run_tests="false" | |
| elif [ "${{ steps.binary-cache.outputs.cache-hit }}" = "true" ] && [ "${{ steps.vars.outputs.stable_image_exists }}" = "true" ]; then | |
| run_tests="false" | |
| fi | |
| echo "run_tests=${run_tests}" >> $GITHUB_OUTPUT | |
| - name: Output variables | |
| run: | | |
| echo docs_only: ${{ github.event.pull_request && steps.docs.outputs.docs_only == 'true' }} | |
| echo k8s_latest: ${{ steps.vars.outputs.k8s_latest }} | |
| echo go_path: ${{ steps.vars.outputs.go_path }} | |
| echo go_code_md5: ${{ steps.vars.outputs.go_code_md5 }} | |
| echo binary_cache_hit: ${{ steps.binary-cache.outputs.cache-hit }} | |
| echo chart_version: ${{ steps.vars.outputs.chart_version }} | |
| echo ic_version: ${{ steps.vars.outputs.ic_version }} | |
| echo docker_md5: ${{ steps.vars.outputs.docker_md5 }} | |
| echo build_tag: ${{ steps.vars.outputs.build_tag }} | |
| echo stable_tag: ${{ steps.vars.outputs.stable_tag }} | |
| echo forked_workflow: ${{ steps.vars.outputs.forked_workflow }} | |
| echo stable_image_exists: ${{ steps.stable_exists.outputs.exists }} | |
| echo additional_tag: ${{ steps.vars.outputs.additional_tag }} | |
| echo 'image_matrix_oss: ${{ steps.vars.outputs.image_matrix_oss }}' | |
| echo 'image_matrix_plus: ${{ steps.vars.outputs.image_matrix_plus }}' | |
| echo 'image_matrix_nap: ${{ steps.vars.outputs.image_matrix_nap }}' | |
| echo 'docker_build: ${{ steps.docker_build.outputs.docker_build }}' | |
| echo 'run_tests: ${{ steps.run_tests.outputs.run_tests }}' | |
| verify-codegen: | |
| name: Verify generated code | |
| runs-on: ubuntu-24.04 | |
| permissions: | |
| contents: read | |
| needs: checks | |
| if: >- | |
| github.repository == 'nginx/kubernetes-ingress' && ( | |
| inputs.force || | |
| needs.checks.outputs.run_tests == 'true' && | |
| needs.checks.outputs.binary_cache_hit != 'true' | |
| ) | |
| env: | |
| GOPROXY: ${{ needs.checks.outputs.go_proxy }} | |
| steps: | |
| - name: Checkout Repository | |
| uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 | |
| - name: Setup Golang Environment | |
| uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0 | |
| with: | |
| go-version-file: go.mod | |
| - name: Check if go.mod and go.sum are up to date | |
| run: go mod tidy && git diff --exit-code -- go.mod go.sum | |
| - name: Check if CRDs changed | |
| run: make update-crds && git diff --name-only --exit-code config/crd/bases | |
| - name: Check if Codegen changed | |
| run: | | |
| cd ../.. && mkdir -p github.com/nginx && mv kubernetes-ingress/kubernetes-ingress github.com/nginx/ && cd github.com/nginx/kubernetes-ingress | |
| make update-codegen && git diff --name-only --exit-code pkg/** | |
| cd ../../.. && mv github.com/nginx/kubernetes-ingress kubernetes-ingress/kubernetes-ingress | |
| - name: Install gofumpt | |
| run: go install mvdan.cc/gofumpt@v0.8.0 | |
| - name: Check if telemetry schema changed | |
| run: | | |
| export PATH=$PATH:$(go env GOPATH)/bin | |
| make telemetry-schema && git diff --name-only --exit-code internal/telemetry | |
| unit-tests: | |
| name: Unit Tests | |
| if: github.repository == 'nginx/kubernetes-ingress' | |
| runs-on: ubuntu-24.04 | |
| permissions: | |
| contents: read | |
| id-token: write | |
| needs: checks | |
| env: | |
| GOPROXY: ${{ needs.checks.outputs.go_proxy }} | |
| steps: | |
| - name: Checkout Repository | |
| uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 | |
| - name: Setup Helm | |
| uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310 # v5.0.1 | |
| with: | |
| version: v3.21.3 # renovate: datasource=github-releases depName=helm/helm | |
| if: >- | |
| inputs.force || | |
| needs.checks.outputs.run_tests == 'true' && | |
| needs.checks.outputs.binary_cache_hit != 'true' | |
| - name: Azure login | |
| uses: azure/login@532459ea530d8321f2fb9bb10d1e0bcf23869a43 # v3.0.0 | |
| with: | |
| client-id: ${{ secrets.AZURE_VAULT_CLIENT_ID }} | |
| tenant-id: ${{ secrets.AZURE_VAULT_TENANT_ID }} | |
| subscription-id: ${{ secrets.AZURE_VAULT_SUBSCRIPTION_ID }} | |
| if: >- | |
| inputs.force || | |
| needs.checks.outputs.forked_workflow == 'false' && | |
| (needs.checks.outputs.run_tests == 'true' && | |
| needs.checks.outputs.binary_cache_hit != 'true') | |
| - name: Setup secrets | |
| id: secrets | |
| run: | | |
| echo "Setting secrets for job" | |
| CODECOV_TOKEN=$(az keyvault secret show --name code-cov --vault-name ${{ secrets.NIC_KEYVAULT_NAME }} --query value -o tsv) | |
| echo "::add-mask::$CODECOV_TOKEN" | |
| echo "CODECOV_TOKEN=$CODECOV_TOKEN" >> $GITHUB_OUTPUT | |
| if: >- | |
| inputs.force || | |
| needs.checks.outputs.forked_workflow == 'false' && | |
| (needs.checks.outputs.run_tests == 'true' && | |
| needs.checks.outputs.binary_cache_hit != 'true') | |
| - name: Setup Golang Environment | |
| uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0 | |
| with: | |
| go-version-file: go.mod | |
| if: >- | |
| inputs.force || | |
| needs.checks.outputs.run_tests == 'true' && | |
| needs.checks.outputs.binary_cache_hit != 'true' | |
| - name: Generate secrets for tests | |
| run: | | |
| make secrets | |
| if: >- | |
| inputs.force || | |
| needs.checks.outputs.run_tests == 'true' && | |
| needs.checks.outputs.binary_cache_hit != 'true' | |
| - name: Run Tests | |
| run: make cover | |
| if: >- | |
| inputs.force || | |
| needs.checks.outputs.run_tests == 'true' && | |
| needs.checks.outputs.binary_cache_hit != 'true' | |
| - name: Upload coverage to Codecov | |
| uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v6.0.2 | |
| with: | |
| files: ./coverage.txt | |
| token: ${{ steps.secrets.outputs.CODECOV_TOKEN }} # required | |
| if: >- | |
| inputs.force || | |
| (needs.checks.outputs.forked_workflow == 'false' && | |
| (needs.checks.outputs.run_tests == 'true' && | |
| needs.checks.outputs.binary_cache_hit != 'true')) | |
| staticcheck: | |
| name: Static Check | |
| runs-on: ubuntu-24.04 | |
| permissions: | |
| contents: read | |
| needs: checks | |
| if: >- | |
| github.repository == 'nginx/kubernetes-ingress' && ( | |
| inputs.force || | |
| needs.checks.outputs.run_tests == 'true' && | |
| needs.checks.outputs.binary_cache_hit != 'true' | |
| ) | |
| env: | |
| GOPROXY: ${{ needs.checks.outputs.go_proxy }} | |
| steps: | |
| - name: Checkout Repository | |
| uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 | |
| - name: Setup Golang Environment | |
| uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0 | |
| with: | |
| go-version-file: go.mod | |
| - name: Generate secrets for tests | |
| run: | | |
| make secrets | |
| - name: Run Static Check | |
| uses: dominikh/staticcheck-action@9716614d4101e79b4340dd97b10e54d68234e431 # v1.4.1 | |
| with: | |
| version: "2026.1" # renovate: datasource=github-releases depName=dominikh/go-tools | |
| install-go: false | |
| use-cache: true | |
| govulncheck: | |
| name: Vulnerability Check | |
| runs-on: ubuntu-24.04 | |
| permissions: | |
| contents: read | |
| needs: checks | |
| if: >- | |
| github.repository == 'nginx/kubernetes-ingress' && ( | |
| inputs.force || | |
| needs.checks.outputs.run_tests == 'true' && | |
| needs.checks.outputs.binary_cache_hit != 'true' | |
| ) | |
| env: | |
| GOPROXY: ${{ needs.checks.outputs.go_proxy }} | |
| steps: | |
| - name: Checkout Repository | |
| uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 | |
| - name: Setup Golang Environment | |
| uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0 | |
| with: | |
| go-version-file: go.mod | |
| - name: Run govulncheck | |
| uses: golang/govulncheck-action@032d45514ae346b1db93c04b0c90b841c370344f # v1.1.0 | |
| with: | |
| repo-checkout: false | |
| cache: true | |
| build-artifacts: | |
| name: Build Artifacts | |
| needs: [checks, unit-tests] | |
| if: github.repository == 'nginx/kubernetes-ingress' | |
| uses: ./.github/workflows/build-artifacts.yml | |
| with: | |
| force: ${{ needs.checks.outputs.docker_build == 'true' }} | |
| branch: ${{ (github.head_ref && needs.checks.outputs.forked_workflow == 'false') && github.head_ref || github.ref }} | |
| tag: ${{ needs.checks.outputs.build_tag }} | |
| docker-md5: ${{ needs.checks.outputs.docker_md5 }} | |
| go-md5: ${{ needs.checks.outputs.go_code_md5 }} | |
| go-path: ${{ needs.checks.outputs.go_path }} | |
| go-proxy: ${{ needs.checks.outputs.go_proxy }} | |
| image-matrix-oss: ${{ needs.checks.outputs.image_matrix_oss }} | |
| image-matrix-plus: ${{ needs.checks.outputs.image_matrix_plus }} | |
| image-matrix-nap: ${{ needs.checks.outputs.image_matrix_nap }} | |
| ic-version: ${{ needs.checks.outputs.ic_version }} | |
| authenticated: ${{ needs.checks.outputs.forked_workflow == 'false' }} | |
| runner: ubuntu-24.04 | |
| write-to-cache: ${{ github.ref_name == github.event.repository.default_branch && true || false }} | |
| permissions: | |
| contents: read | |
| actions: read | |
| id-token: write | |
| packages: write | |
| pull-requests: write # for scout report | |
| secrets: inherit | |
| tag-target: | |
| name: Tag untested image with PR number | |
| needs: [checks, build-artifacts] | |
| permissions: | |
| contents: read # To checkout repository | |
| id-token: write # To sign into Google Container Registry | |
| uses: ./.github/workflows/retag-images.yml | |
| with: | |
| source_tag: ${{ needs.checks.outputs.build_tag }} | |
| target_tag: ${{ needs.checks.outputs.additional_tag }} | |
| dry_run: false | |
| secrets: inherit | |
| if: >- | |
| github.repository == 'nginx/kubernetes-ingress' && ( | |
| needs.checks.outputs.forked_workflow == 'false' && | |
| (needs.checks.outputs.run_tests == 'true' || | |
| needs.checks.outputs.docker_build == 'true') | |
| ) | |
| package-tests: | |
| if: >- | |
| github.repository == 'nginx/kubernetes-ingress' && ( | |
| needs.checks.outputs.run_tests == 'true' || | |
| needs.checks.outputs.docker_build == 'true' | |
| ) | |
| name: Package Tests | |
| runs-on: ubuntu-24.04 | |
| needs: [checks, build-artifacts] | |
| permissions: | |
| contents: read | |
| pull-requests: write # for package report | |
| id-token: write | |
| steps: | |
| - name: Checkout Repository | |
| uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 | |
| - name: Setup QEMU | |
| uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4.2.0 | |
| with: | |
| platforms: arm64 | |
| if: ${{ needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' }} | |
| - name: Azure login | |
| uses: azure/login@532459ea530d8321f2fb9bb10d1e0bcf23869a43 # v3.0.0 | |
| with: | |
| client-id: ${{ secrets.AZURE_VAULT_CLIENT_ID }} | |
| tenant-id: ${{ secrets.AZURE_VAULT_TENANT_ID }} | |
| subscription-id: ${{ secrets.AZURE_VAULT_SUBSCRIPTION_ID }} | |
| if: ${{ needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' }} | |
| - name: Setup secrets | |
| id: secrets | |
| run: | | |
| echo "Setting secrets for job" | |
| GCR_WORKLOAD_ID=$(az keyvault secret show --name gcr-workload-identity --vault-name ${{ secrets.NIC_KEYVAULT_NAME }} --query value -o tsv) | |
| echo "::add-mask::$GCR_WORKLOAD_ID" | |
| echo "GCR_WORKLOAD_ID=$GCR_WORKLOAD_ID" >> $GITHUB_OUTPUT | |
| GCR_SERVICE_ACCOUNT=$(az keyvault secret show --name kic-pipeline-gcr-sa --vault-name ${{ secrets.NIC_KEYVAULT_NAME }} --query value -o tsv) | |
| echo "::add-mask::$GCR_SERVICE_ACCOUNT" | |
| echo "GCR_SERVICE_ACCOUNT=$GCR_SERVICE_ACCOUNT" >> $GITHUB_OUTPUT | |
| if: ${{ needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' }} | |
| - name: Authenticate to Google Cloud | |
| id: auth | |
| uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0 | |
| with: | |
| token_format: access_token | |
| workload_identity_provider: ${{ steps.secrets.outputs.GCR_WORKLOAD_ID }} | |
| service_account: ${{ steps.secrets.outputs.GCR_SERVICE_ACCOUNT }} | |
| if: ${{ needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' }} | |
| - name: Login to GCR | |
| uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0 | |
| with: | |
| registry: gcr.io | |
| username: oauth2accesstoken | |
| password: ${{ steps.auth.outputs.access_token }} | |
| if: ${{ needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' }} | |
| - name: Install Python dependencies | |
| run: | | |
| make -f tests/Makefile setup-venv | |
| if: ${{ needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' }} | |
| - name: Run tests | |
| id: packages | |
| run: | | |
| source tests/venv/bin/activate | |
| python tests/scripts/check_container_packages.py --tag ${{ needs.checks.outputs.build_tag }} --log package_output.txt | |
| if: ${{ needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' }} | |
| - name: Add comment | |
| run: | | |
| # make sure the comment is formatted correctly, as a code block | |
| echo '### Package Report' > output.txt | |
| echo '<details>' >> output.txt | |
| cat package_output.txt | sed -r 's#^(.*)$#\1<br>#' >> output.txt | |
| echo '</details>' >> output.txt | |
| gh pr comment --edit-last --create-if-none ${{ github.event.pull_request.number }} -F output.txt | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| if: ${{ ( needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' ) && github.event.pull_request }} | |
| helm-tests: | |
| if: >- | |
| github.repository == 'nginx/kubernetes-ingress' && ( | |
| needs.checks.outputs.run_tests == 'true' || | |
| needs.checks.outputs.docker_build == 'true' | |
| ) | |
| name: Helm Tests ${{ matrix.base-os }} | |
| runs-on: ubuntu-24.04 | |
| needs: [checks, build-artifacts] | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - base-os: debian | |
| image: gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress | |
| tag: ${{ needs.checks.outputs.build_tag }} | |
| type: oss | |
| - base-os: debian-plus | |
| image: gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress | |
| tag: ${{ needs.checks.outputs.build_tag }} | |
| type: plus | |
| permissions: | |
| contents: read | |
| id-token: write | |
| steps: | |
| - name: Checkout Repository | |
| uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 | |
| - name: Setup Helm | |
| uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310 # v5.0.1 | |
| with: | |
| version: v3.21.3 # renovate: datasource=github-releases depName=helm/helm | |
| - name: Azure login | |
| uses: azure/login@532459ea530d8321f2fb9bb10d1e0bcf23869a43 # v3.0.0 | |
| with: | |
| client-id: ${{ secrets.AZURE_VAULT_CLIENT_ID }} | |
| tenant-id: ${{ secrets.AZURE_VAULT_TENANT_ID }} | |
| subscription-id: ${{ secrets.AZURE_VAULT_SUBSCRIPTION_ID }} | |
| if: ${{ needs.checks.outputs.forked_workflow != 'true' }} | |
| - name: Setup secrets | |
| id: secrets | |
| run: | | |
| echo "Setting secrets for job" | |
| GCR_WORKLOAD_ID=$(az keyvault secret show --name gcr-workload-identity --vault-name ${{ secrets.NIC_KEYVAULT_NAME }} --query value -o tsv) | |
| echo "::add-mask::$GCR_WORKLOAD_ID" | |
| echo "GCR_WORKLOAD_ID=$GCR_WORKLOAD_ID" >> $GITHUB_OUTPUT | |
| GCR_SERVICE_ACCOUNT=$(az keyvault secret show --name kic-pipeline-gcr-sa --vault-name ${{ secrets.NIC_KEYVAULT_NAME }} --query value -o tsv) | |
| echo "::add-mask::$GCR_SERVICE_ACCOUNT" | |
| echo "GCR_SERVICE_ACCOUNT=$GCR_SERVICE_ACCOUNT" >> $GITHUB_OUTPUT | |
| PLUS_CREDS=$(az keyvault secret show --name plus-creds --vault-name ${{ secrets.NIC_KEYVAULT_NAME }} --query value -o tsv) | |
| echo "::add-mask::$PLUS_CREDS" | |
| PLUS_JWT=$(echo $PLUS_CREDS | jq -r '.jwt') | |
| echo "::add-mask::$PLUS_JWT" | |
| echo "PLUS_JWT=$PLUS_JWT" >> $GITHUB_OUTPUT | |
| IFS=@ CERT=$(echo $PLUS_CREDS | jq -r '.crt') | |
| while read -r line; do | |
| echo "::add-mask::${line}" | |
| done <<< "${CERT}" | |
| echo $CERT > nginx-repo.crt | |
| IFS=@ KEY=$(echo $PLUS_CREDS | jq -r '.key') | |
| while read -r line; do | |
| echo "::add-mask::${line}" | |
| done <<< "${KEY}" | |
| echo $KEY > nginx-repo.key | |
| if: ${{ needs.checks.outputs.forked_workflow != 'true' }} | |
| - name: Authenticate to Google Cloud | |
| id: auth | |
| uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0 | |
| with: | |
| token_format: access_token | |
| workload_identity_provider: ${{ steps.secrets.outputs.GCR_WORKLOAD_ID }} | |
| service_account: ${{ steps.secrets.outputs.GCR_SERVICE_ACCOUNT }} | |
| if: ${{ needs.checks.outputs.forked_workflow == 'false' }} | |
| - name: Login to GCR | |
| uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0 | |
| with: | |
| registry: gcr.io | |
| username: oauth2accesstoken | |
| password: ${{ steps.auth.outputs.access_token }} | |
| if: ${{ needs.checks.outputs.forked_workflow == 'false' }} | |
| - name: Check if stable image exists | |
| id: stable_exists | |
| run: | | |
| if docker pull ${{ matrix.image }}:${{ needs.checks.outputs.stable_tag }}; then | |
| echo "exists=true" >> $GITHUB_OUTPUT | |
| fi | |
| if: ${{ needs.checks.outputs.forked_workflow == 'false' }} | |
| - name: Pull build image | |
| run: | | |
| docker pull ${{ matrix.image }}:${{ needs.checks.outputs.build_tag }} | |
| if: ${{ needs.checks.outputs.forked_workflow == 'false' && steps.stable_exists.outputs.exists != 'true' }} | |
| - name: Fetch Cached Artifacts | |
| uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5.1.0 | |
| with: | |
| path: ${{ github.workspace }}/dist | |
| key: nginx-ingress-${{ needs.checks.outputs.go_code_md5 }} | |
| if: ${{ needs.checks.outputs.forked_workflow == 'true' }} | |
| - name: Docker Buildx | |
| uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0 | |
| if: ${{ needs.checks.outputs.forked_workflow == 'true' }} | |
| - name: Build Docker Image ${{ matrix.base-os }} | |
| uses: ./.github/actions/build-push-retry | |
| with: | |
| file: build/Dockerfile | |
| context: "." | |
| cache-from: type=gha,scope=${{ matrix.base-os }} | |
| target: goreleaser | |
| tags: "${{ matrix.image }}:${{ matrix.tag }}" | |
| pull: true | |
| load: true | |
| build-args: | | |
| BUILD_OS=${{ matrix.base-os }} | |
| IC_VERSION=CI | |
| secret-files: | | |
| ${{ matrix.type == 'plus' && 'nginx-repo.crt=nginx-repo.crt' || '' }} | |
| ${{ matrix.type == 'plus' && 'nginx-repo.key=nginx-repo.key' || '' }} | |
| if: ${{ needs.checks.outputs.forked_workflow == 'true' }} | |
| - name: Deploy Kubernetes | |
| id: k8s | |
| run: | | |
| kind create cluster --name ${{ github.run_id }} --image=kindest/node:v${{ needs.checks.outputs.k8s_latest }} --wait 75s | |
| docker version | |
| docker save "${{ matrix.image }}:${{ matrix.tag }}" | \ | |
| docker exec -i ${{ github.run_id }}-control-plane \ | |
| ctr --namespace=k8s.io images import - | |
| echo "DEBUG: Kind setup complete!" | |
| if: ${{ steps.stable_exists.outputs.exists != 'true' }} | |
| - name: Create Plus Secret | |
| run: kubectl create secret generic license-token --from-literal=license.jwt="${{ steps.secrets.outputs.PLUS_JWT }}" --type="nginx.com/license" | |
| if: ${{ matrix.type == 'plus' && steps.stable_exists.outputs.exists != 'true' }} | |
| - name: Install Chart | |
| run: > | |
| helm install | |
| ${{ matrix.type }} | |
| . | |
| --set controller.image.repository=${{ matrix.image }} | |
| --set controller.image.tag=${{ matrix.tag }} | |
| --set controller.service.type=NodePort | |
| --set controller.nginxplus=${{ contains(matrix.type, 'plus') && 'true' || 'false' }} | |
| --set controller.telemetryReporting.enable=false | |
| --wait | |
| working-directory: ${{ github.workspace }}/charts/nginx-ingress | |
| if: ${{ steps.stable_exists.outputs.exists != 'true' }} | |
| - name: Expose Test Ingresses | |
| run: | | |
| kubectl port-forward service/${{ matrix.type }}-nginx-ingress-controller 8080:80 8443:443 & | |
| if: ${{ steps.stable_exists.outputs.exists != 'true' }} | |
| - name: Test HTTP | |
| run: | | |
| counter=0 | |
| max_attempts=5 | |
| until [ $(curl --write-out %{http_code} -s --output /dev/null http://localhost:8080) -eq 404 ]; do | |
| if [ ${counter} -eq ${max_attempts} ]; then | |
| exit 1 | |
| fi | |
| printf '.'; counter=$(($counter+1)); sleep 5; | |
| done | |
| if: ${{ steps.stable_exists.outputs.exists != 'true' }} | |
| - name: Test HTTPS | |
| run: | | |
| counter=0 | |
| max_attempts=5 | |
| until [ $(curl --write-out %{http_code} -ks --output /dev/null https://localhost:8443) -eq 000 ]; do | |
| if [ ${counter} -eq ${max_attempts} ]; then | |
| exit 1 | |
| fi | |
| printf '.'; counter=$(($counter+1)); sleep 5; | |
| done | |
| if: ${{ steps.stable_exists.outputs.exists != 'true' }} | |
| - name: Clean up secrets | |
| run: | | |
| rm -f nginx-repo.crt nginx-repo.key | |
| if: always() | |
| setup-matrix: | |
| if: >- | |
| github.repository == 'nginx/kubernetes-ingress' && ( | |
| needs.checks.outputs.run_tests == 'true' || | |
| needs.checks.outputs.docker_build == 'true' | |
| ) | |
| name: Setup Matrix for Smoke Tests | |
| runs-on: ubuntu-24.04 | |
| needs: [build-artifacts, checks] | |
| permissions: | |
| contents: read | |
| id-token: write | |
| outputs: | |
| matrix_oss: ${{ steps.set-matrix.outputs.matrix_oss }} | |
| matrix_plus: ${{ steps.set-matrix.outputs.matrix_plus }} | |
| matrix_nap: ${{ steps.set-matrix.outputs.matrix_nap }} | |
| steps: | |
| - name: Checkout Repository | |
| uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 | |
| - id: set-matrix | |
| run: | | |
| echo "matrix_oss=$(cat .github/data/matrix-smoke-oss.json | jq -c --arg latest "${{ needs.checks.outputs.k8s_latest }}" '.k8s += [$latest]')" >> $GITHUB_OUTPUT | |
| echo "matrix_plus=$(cat .github/data/matrix-smoke-plus.json | jq -c --arg latest "${{ needs.checks.outputs.k8s_latest }}" '.k8s += [$latest]')" >> $GITHUB_OUTPUT | |
| echo "matrix_nap=$(cat .github/data/matrix-smoke-nap.json | jq -c --arg latest "${{ needs.checks.outputs.k8s_latest }}" '.k8s += [$latest]')" >> $GITHUB_OUTPUT | |
| - name: Docker Buildx | |
| uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0 | |
| - name: Azure login | |
| uses: azure/login@532459ea530d8321f2fb9bb10d1e0bcf23869a43 # v3.0.0 | |
| with: | |
| client-id: ${{ secrets.AZURE_VAULT_CLIENT_ID }} | |
| tenant-id: ${{ secrets.AZURE_VAULT_TENANT_ID }} | |
| subscription-id: ${{ secrets.AZURE_VAULT_SUBSCRIPTION_ID }} | |
| if: ${{ needs.checks.outputs.forked_workflow == 'false' }} | |
| - name: Setup secrets | |
| id: secrets | |
| run: | | |
| echo "Setting secrets for job" | |
| GCR_WORKLOAD_ID=$(az keyvault secret show --name gcr-workload-identity --vault-name ${{ secrets.NIC_KEYVAULT_NAME }} --query value -o tsv) | |
| echo "::add-mask::$GCR_WORKLOAD_ID" | |
| echo "GCR_WORKLOAD_ID=$GCR_WORKLOAD_ID" >> $GITHUB_OUTPUT | |
| GCR_SERVICE_ACCOUNT=$(az keyvault secret show --name kic-pipeline-gcr-sa --vault-name ${{ secrets.NIC_KEYVAULT_NAME }} --query value -o tsv) | |
| echo "::add-mask::$GCR_SERVICE_ACCOUNT" | |
| echo "GCR_SERVICE_ACCOUNT=$GCR_SERVICE_ACCOUNT" >> $GITHUB_OUTPUT | |
| if: ${{ needs.checks.outputs.forked_workflow == 'false' }} | |
| - name: Authenticate to Google Cloud | |
| id: auth | |
| uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0 | |
| with: | |
| token_format: access_token | |
| workload_identity_provider: ${{ steps.secrets.outputs.GCR_WORKLOAD_ID }} | |
| service_account: ${{ steps.secrets.outputs.GCR_SERVICE_ACCOUNT }} | |
| if: ${{ needs.checks.outputs.forked_workflow == 'false' }} | |
| - name: Login to GCR | |
| uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0 | |
| with: | |
| registry: gcr.io | |
| username: oauth2accesstoken | |
| password: ${{ steps.auth.outputs.access_token }} | |
| if: ${{ needs.checks.outputs.forked_workflow == 'false' }} | |
| - name: Check if test image exists | |
| id: check-image | |
| run: | | |
| docker pull gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/test-runner:${{ hashFiles('./tests/requirements.txt', './tests/Dockerfile') || 'latest' }} | |
| shell: bash | |
| continue-on-error: true | |
| if: ${{ needs.checks.outputs.forked_workflow == 'false' }} | |
| - name: Build Test-Runner Container | |
| uses: ./.github/actions/build-push-retry | |
| with: | |
| file: tests/Dockerfile | |
| context: "." | |
| cache-from: type=gha,scope=test-runner | |
| tags: "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/test-runner:${{ hashFiles('./tests/requirements.txt', './tests/Dockerfile') || 'latest' }}" | |
| pull: true | |
| push: ${{ needs.checks.outputs.forked_workflow == 'false' }} | |
| load: false | |
| if: ${{ steps.check-image.outcome == 'failure' }} | |
| smoke-tests-oss: | |
| if: >- | |
| github.repository == 'nginx/kubernetes-ingress' && ( | |
| needs.checks.outputs.run_tests == 'true' || | |
| needs.checks.outputs.docker_build == 'true' | |
| ) | |
| name: ${{ matrix.images.label }} ${{ matrix.images.image }} ${{ matrix.k8s }} smoke tests | |
| needs: | |
| - checks | |
| - setup-matrix | |
| - build-artifacts | |
| strategy: | |
| fail-fast: false | |
| matrix: ${{ fromJSON(needs.setup-matrix.outputs.matrix_oss) }} | |
| permissions: | |
| contents: read | |
| id-token: write | |
| uses: ./.github/workflows/setup-smoke.yml | |
| secrets: inherit | |
| with: | |
| image: ${{ matrix.images.image }} | |
| target: ${{ matrix.images.target }} | |
| nap-modules: ${{ matrix.images.nap_modules }} | |
| marker: ${{ matrix.images.marker }} | |
| label: ${{ matrix.images.label }} | |
| go-md5: ${{ needs.checks.outputs.go_code_md5 }} | |
| build-tag: ${{ needs.checks.outputs.build_tag }} | |
| stable-tag: ${{ needs.checks.outputs.stable_tag }} | |
| authenticated: ${{ needs.checks.outputs.forked_workflow == 'false' }} | |
| k8s-version: ${{ matrix.k8s }} | |
| force: ${{ needs.checks.outputs.run_tests == 'true' }} | |
| smoke-tests-plus: | |
| if: >- | |
| github.repository == 'nginx/kubernetes-ingress' && ( | |
| needs.checks.outputs.run_tests == 'true' || | |
| needs.checks.outputs.docker_build == 'true' | |
| ) | |
| name: ${{ matrix.images.label }} ${{ matrix.images.image }} ${{ matrix.k8s }} smoke tests | |
| needs: | |
| - checks | |
| - setup-matrix | |
| - build-artifacts | |
| strategy: | |
| fail-fast: false | |
| matrix: ${{ fromJSON(needs.setup-matrix.outputs.matrix_plus) }} | |
| permissions: | |
| contents: read | |
| id-token: write | |
| uses: ./.github/workflows/setup-smoke.yml | |
| secrets: inherit | |
| with: | |
| image: ${{ matrix.images.image }} | |
| target: ${{ matrix.images.target }} | |
| nap-modules: ${{ matrix.images.nap_modules }} | |
| marker: ${{ matrix.images.marker }} | |
| label: ${{ matrix.images.label }} | |
| go-md5: ${{ needs.checks.outputs.go_code_md5 }} | |
| build-tag: ${{ needs.checks.outputs.build_tag }} | |
| stable-tag: ${{ needs.checks.outputs.stable_tag }} | |
| authenticated: ${{ needs.checks.outputs.forked_workflow == 'false' }} | |
| k8s-version: ${{ matrix.k8s }} | |
| force: ${{ needs.checks.outputs.run_tests == 'true' }} | |
| smoke-tests-nap: | |
| if: >- | |
| github.repository == 'nginx/kubernetes-ingress' && ( | |
| needs.checks.outputs.run_tests == 'true' || | |
| needs.checks.outputs.docker_build == 'true' | |
| ) | |
| name: ${{ matrix.images.label }} ${{ matrix.images.image }} ${{ matrix.k8s }} smoke tests | |
| needs: | |
| - checks | |
| - setup-matrix | |
| - build-artifacts | |
| strategy: | |
| fail-fast: false | |
| matrix: ${{ fromJSON(needs.setup-matrix.outputs.matrix_nap) }} | |
| permissions: | |
| contents: read | |
| id-token: write | |
| uses: ./.github/workflows/setup-smoke.yml | |
| secrets: inherit | |
| with: | |
| image: ${{ matrix.images.image }} | |
| target: ${{ matrix.images.target }} | |
| nap-modules: ${{ matrix.images.nap_modules }} | |
| marker: ${{ matrix.images.marker }} | |
| label: ${{ matrix.images.label }} | |
| go-md5: ${{ needs.checks.outputs.go_code_md5 }} | |
| build-tag: ${{ needs.checks.outputs.build_tag }} | |
| stable-tag: ${{ needs.checks.outputs.stable_tag }} | |
| authenticated: ${{ needs.checks.outputs.forked_workflow == 'false' }} | |
| k8s-version: ${{ matrix.k8s }} | |
| force: ${{ needs.checks.outputs.run_tests == 'true' }} | |
| tag-stable: | |
| name: Tag tested image as stable | |
| needs: [checks, build-artifacts, smoke-tests-oss, smoke-tests-plus, smoke-tests-nap] | |
| permissions: | |
| contents: read # To checkout repository | |
| id-token: write # To sign into Google Container Registry | |
| uses: ./.github/workflows/retag-images.yml | |
| with: | |
| source_tag: ${{ needs.checks.outputs.build_tag }} | |
| target_tag: ${{ needs.checks.outputs.stable_tag }} | |
| dry_run: false | |
| secrets: inherit | |
| if: >- | |
| github.repository == 'nginx/kubernetes-ingress' && ( | |
| (needs.checks.outputs.forked_workflow == 'false' && | |
| needs.checks.outputs.stable_image_exists != 'true') | |
| ) | |
| final-results: | |
| if: github.repository == 'nginx/kubernetes-ingress' && (!cancelled()) | |
| runs-on: ubuntu-24.04 | |
| name: Final CI Results | |
| needs: [tag-stable, build-artifacts, smoke-tests-oss, smoke-tests-plus, smoke-tests-nap, package-tests, helm-tests, staticcheck, govulncheck] | |
| steps: | |
| - run: | | |
| tagResult="${{ needs.tag-stable.result }}" | |
| packageResult="${{ needs.package-tests.result }}" | |
| helmResult="${{ needs.helm-tests.result }}" | |
| smokeOSSResult="${{ needs.smoke-tests-oss.result }}" | |
| smokePlusResult="${{ needs.smoke-tests-plus.result }}" | |
| smokeNAPResult="${{ needs.smoke-tests-nap.result }}" | |
| buildArtifactsResult="${{ needs.build-artifacts.result }}" | |
| staticcheckResult="${{ needs.staticcheck.result }}" | |
| govulncheckResult="${{ needs.govulncheck.result }}" | |
| if [[ $tagResult != "success" && $tagResult != "skipped" ]]; then | |
| exit 1 | |
| fi | |
| if [[ $smokeOSSResult != "success" && $smokeOSSResult != "skipped" ]]; then | |
| exit 1 | |
| fi | |
| if [[ $smokePlusResult != "success" && $smokePlusResult != "skipped" ]]; then | |
| exit 1 | |
| fi | |
| if [[ $smokeNAPResult != "success" && $smokeNAPResult != "skipped" ]]; then | |
| exit 1 | |
| fi | |
| if [[ $buildArtifactsResult != "success" && $buildArtifactsResult != "skipped" ]]; then | |
| exit 1 | |
| fi | |
| if [[ $helmResult != "success" && $helmResult != "skipped" ]]; then | |
| exit 1 | |
| fi | |
| if [[ $packageResult != "success" && $packageResult != "skipped" ]]; then | |
| exit 1 | |
| fi | |
| if [[ $staticcheckResult != "success" && $staticcheckResult != "skipped" ]]; then | |
| exit 1 | |
| fi | |
| if [[ $govulncheckResult != "success" && $govulncheckResult != "skipped" ]]; then | |
| exit 1 | |
| fi | |
| trigger-image-promotion: | |
| name: Promote images on Force Run | |
| needs: | |
| - final-results | |
| - build-artifacts | |
| permissions: | |
| contents: write # for pushing to Helm Charts repository | |
| id-token: write # To sign into Google Container Registry | |
| actions: read | |
| packages: write # for helm to push to GHCR | |
| security-events: write | |
| pull-requests: write # for scout report | |
| uses: ./.github/workflows/image-promotion.yml | |
| secrets: inherit | |
| if: github.repository == 'nginx/kubernetes-ingress' && (inputs.force && (github.ref_name == 'main' || startsWith(github.ref_name, 'release-'))) |