diff --git a/.github/workflows/test-destroy.yml b/.github/workflows/test-destroy.yml index 03922d9..5dd2fc5 100644 --- a/.github/workflows/test-destroy.yml +++ b/.github/workflows/test-destroy.yml @@ -30,7 +30,7 @@ jobs: password: ${{ secrets.DOCKERHUB_PASSWORD }} steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: path: ./action @@ -84,7 +84,7 @@ jobs: password: ${{ secrets.DOCKERHUB_PASSWORD }} steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: path: ./action @@ -151,7 +151,7 @@ jobs: environment: terratest needs: [setup, test] steps: - - uses: nick-fields/assert-action@v2 + - uses: nick-fields/assert-action@0efd6166067d9c59d89c710fab4f79fb066f8985 # v4.0.1 with: expected: "" actual: "${{ needs.test.outputs.sha }}" @@ -173,7 +173,7 @@ jobs: type: file token: ${{ steps.github-app.outputs.token }} - - uses: nick-fields/assert-action@v2 + - uses: nick-fields/assert-action@0efd6166067d9c59d89c710fab4f79fb066f8985 # v4.0.1 with: expected: "false" actual: "${{ steps.resources.outputs.exists }}" diff --git a/.github/workflows/test-helm-raw-default-kube-version.yml b/.github/workflows/test-helm-raw-default-kube-version.yml index 91ea061..a453385 100644 --- a/.github/workflows/test-helm-raw-default-kube-version.yml +++ b/.github/workflows/test-helm-raw-default-kube-version.yml @@ -47,7 +47,7 @@ jobs: password: ${{ secrets.DOCKERHUB_PASSWORD }} steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: path: ./action @@ -109,17 +109,17 @@ jobs: environment: terratest needs: [setup, test] steps: - - uses: nick-fields/assert-action@v2 + - uses: nick-fields/assert-action@0efd6166067d9c59d89c710fab4f79fb066f8985 # v4.0.1 with: expected: "success" actual: "${{ needs.test.outputs.status }}" - - uses: nick-fields/assert-action@v2 + - uses: nick-fields/assert-action@0efd6166067d9c59d89c710fab4f79fb066f8985 # v4.0.1 with: expected: "https://example-app.example.com/dashboard" actual: "${{ needs.test.outputs.result }}" - - uses: nick-fields/assert-action@v2 + - uses: nick-fields/assert-action@0efd6166067d9c59d89c710fab4f79fb066f8985 # v4.0.1 with: expected: "" actual: "${{ needs.test.outputs.sha }}" @@ -133,7 +133,7 @@ jobs: owner: 'cloudposse-tests' - name: Checkout Argo Configuration - uses: actions/checkout@v6 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: repository: cloudposse-tests/argocd-deploy-non-prod-test ref: ${{ needs.test.outputs.sha }} @@ -150,7 +150,7 @@ jobs: ) echo "value=${image}" >> $GITHUB_OUTPUT - - uses: nick-fields/assert-action@v2 + - uses: nick-fields/assert-action@0efd6166067d9c59d89c710fab4f79fb066f8985 # v4.0.1 with: expected: "nginx:${{ needs.setup.outputs.random }}" actual: "${{ steps.image.outputs.value }}" @@ -165,11 +165,26 @@ jobs: ) echo "value=${ingress}" >> $GITHUB_OUTPUT - - uses: nick-fields/assert-action@v2 + - uses: nick-fields/assert-action@0efd6166067d9c59d89c710fab4f79fb066f8985 # v4.0.1 with: expected: "networking.k8s.io/v1" actual: "${{ steps.ingress.outputs.value }}" + - name: Get Deployment ID presence + id: deployment_id + shell: bash + run: |- + has_deployment_id=$( \ + yq eval-all 'has("deployment_id")' \ + ./assert/plat/ue2-sandbox/apps/staging/test-app/config.yaml \ + ) + echo "value=${has_deployment_id}" >> $GITHUB_OUTPUT + + - uses: nick-fields/assert-action@0efd6166067d9c59d89c710fab4f79fb066f8985 # v4.0.1 + with: + expected: "false" + actual: "${{ steps.deployment_id.outputs.value }}" + teardown: runs-on: ubuntu-latest needs: [assert] diff --git a/.github/workflows/test-helm-raw.yml b/.github/workflows/test-helm-raw.yml index 88971b3..a7f1996 100644 --- a/.github/workflows/test-helm-raw.yml +++ b/.github/workflows/test-helm-raw.yml @@ -47,7 +47,7 @@ jobs: password: ${{ secrets.DOCKERHUB_PASSWORD }} steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: path: ./action @@ -96,6 +96,7 @@ jobs: github-pat: ${{ steps.github-app.outputs.token }} image: nginx image-tag: ${{ needs.setup.outputs.random }} + deployment-id: ${{ github.run_id }}-${{ github.run_attempt }} env: AWS_ACCESS_KEY_ID: test AWS_SECRET_ACCESS_KEY: test @@ -115,17 +116,17 @@ jobs: environment: terratest needs: [setup, test] steps: - - uses: nick-fields/assert-action@v2 + - uses: nick-fields/assert-action@0efd6166067d9c59d89c710fab4f79fb066f8985 # v4.0.1 with: expected: "success" actual: "${{ needs.test.outputs.status }}" - - uses: nick-fields/assert-action@v2 + - uses: nick-fields/assert-action@0efd6166067d9c59d89c710fab4f79fb066f8985 # v4.0.1 with: expected: "https://example-app.example.com/dashboard" actual: "${{ needs.test.outputs.result }}" - - uses: nick-fields/assert-action@v2 + - uses: nick-fields/assert-action@0efd6166067d9c59d89c710fab4f79fb066f8985 # v4.0.1 with: expected: "" actual: "${{ needs.test.outputs.sha }}" @@ -139,7 +140,7 @@ jobs: owner: 'cloudposse-tests' - name: Checkout Argo Configuration - uses: actions/checkout@v6 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: repository: cloudposse-tests/argocd-deploy-non-prod-test ref: ${{ needs.test.outputs.sha }} @@ -156,7 +157,7 @@ jobs: ) echo "value=${image}" >> $GITHUB_OUTPUT - - uses: nick-fields/assert-action@v2 + - uses: nick-fields/assert-action@0efd6166067d9c59d89c710fab4f79fb066f8985 # v4.0.1 with: expected: "nginx:${{ needs.setup.outputs.random }}" actual: "${{ steps.image.outputs.value }}" @@ -171,7 +172,7 @@ jobs: ) echo "value=${ingress}" >> $GITHUB_OUTPUT - - uses: nick-fields/assert-action@v2 + - uses: nick-fields/assert-action@0efd6166067d9c59d89c710fab4f79fb066f8985 # v4.0.1 with: expected: "networking.k8s.io/v1beta1" actual: "${{ steps.ingress.outputs.value }}" @@ -186,11 +187,26 @@ jobs: ) echo "value=${name}" >> $GITHUB_OUTPUT - - uses: nick-fields/assert-action@v2 + - uses: nick-fields/assert-action@0efd6166067d9c59d89c710fab4f79fb066f8985 # v4.0.1 with: expected: "staging.test-app" actual: "${{ steps.name.outputs.value }}" + - name: Get Deployment ID + id: deployment_id + shell: bash + run: |- + deployment_id=$( \ + yq eval-all '.deployment_id' \ + ./assert/plat/ue2-sandbox/apps/staging/test-app/config.yaml \ + ) + echo "value=${deployment_id}" >> $GITHUB_OUTPUT + + - uses: nick-fields/assert-action@0efd6166067d9c59d89c710fab4f79fb066f8985 # v4.0.1 + with: + expected: "${{ github.run_id }}-${{ github.run_attempt }}" + actual: "${{ steps.deployment_id.outputs.value }}" + teardown: runs-on: ubuntu-latest needs: [assert] diff --git a/.github/workflows/test-helmfile-raw-default-kube-version.yml b/.github/workflows/test-helmfile-raw-default-kube-version.yml index 1cbb8a1..36226b6 100644 --- a/.github/workflows/test-helmfile-raw-default-kube-version.yml +++ b/.github/workflows/test-helmfile-raw-default-kube-version.yml @@ -48,7 +48,7 @@ jobs: password: ${{ secrets.DOCKERHUB_PASSWORD }} steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: path: ./action @@ -112,17 +112,17 @@ jobs: environment: terratest needs: [setup, test] steps: - - uses: nick-fields/assert-action@v2 + - uses: nick-fields/assert-action@0efd6166067d9c59d89c710fab4f79fb066f8985 # v4.0.1 with: expected: "success" actual: "${{ needs.test.outputs.status }}" - - uses: nick-fields/assert-action@v2 + - uses: nick-fields/assert-action@0efd6166067d9c59d89c710fab4f79fb066f8985 # v4.0.1 with: expected: "https://example-app.example.com/dashboard" actual: "${{ needs.test.outputs.result }}" - - uses: nick-fields/assert-action@v2 + - uses: nick-fields/assert-action@0efd6166067d9c59d89c710fab4f79fb066f8985 # v4.0.1 with: expected: "" actual: "${{ needs.test.outputs.sha }}" @@ -136,7 +136,7 @@ jobs: owner: 'cloudposse-tests' - name: Checkout Argo Configuration - uses: actions/checkout@v6 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: repository: cloudposse-tests/argocd-deploy-non-prod-test ref: ${{ needs.test.outputs.sha }} @@ -153,7 +153,7 @@ jobs: ) echo "value=${image}" >> $GITHUB_OUTPUT - - uses: nick-fields/assert-action@v2 + - uses: nick-fields/assert-action@0efd6166067d9c59d89c710fab4f79fb066f8985 # v4.0.1 with: expected: "nginx:${{ needs.setup.outputs.random }}" actual: "${{ steps.image.outputs.value }}" @@ -168,7 +168,7 @@ jobs: ) echo "value=${ingress}" >> $GITHUB_OUTPUT - - uses: nick-fields/assert-action@v2 + - uses: nick-fields/assert-action@0efd6166067d9c59d89c710fab4f79fb066f8985 # v4.0.1 with: expected: "networking.k8s.io/v1" actual: "${{ steps.ingress.outputs.value }}" @@ -183,7 +183,7 @@ jobs: ) echo "value=${app_commit}" >> $GITHUB_OUTPUT - - uses: nick-fields/assert-action@v2 + - uses: nick-fields/assert-action@0efd6166067d9c59d89c710fab4f79fb066f8985 # v4.0.1 with: expected: "${{ github.sha }}" actual: "${{ steps.app_commit.outputs.value }}" diff --git a/.github/workflows/test-helmfile-raw.yml b/.github/workflows/test-helmfile-raw.yml index dea7244..ae7e9e1 100644 --- a/.github/workflows/test-helmfile-raw.yml +++ b/.github/workflows/test-helmfile-raw.yml @@ -54,7 +54,7 @@ jobs: password: ${{ secrets.DOCKERHUB_PASSWORD }} steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: path: ./action @@ -133,7 +133,7 @@ jobs: owner: 'cloudposse-tests' - name: Checkout Argo Configuration - uses: actions/checkout@v6 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: repository: cloudposse-tests/argocd-deploy-non-prod-test token: ${{ steps.github-app.outputs.token }} @@ -195,17 +195,17 @@ jobs: environment: terratest needs: [setup, test, argocd] steps: - - uses: nick-fields/assert-action@v2 + - uses: nick-fields/assert-action@0efd6166067d9c59d89c710fab4f79fb066f8985 # v4.0.1 with: expected: "success" actual: "${{ needs.test.outputs.status }}" - - uses: nick-fields/assert-action@v2 + - uses: nick-fields/assert-action@0efd6166067d9c59d89c710fab4f79fb066f8985 # v4.0.1 with: expected: "https://example-app.example.com/dashboard" actual: "${{ needs.test.outputs.result }}" - - uses: nick-fields/assert-action@v2 + - uses: nick-fields/assert-action@0efd6166067d9c59d89c710fab4f79fb066f8985 # v4.0.1 with: expected: "" actual: "${{ needs.test.outputs.sha }}" @@ -219,7 +219,7 @@ jobs: owner: 'cloudposse-tests' - name: Checkout Argo Configuration - uses: actions/checkout@v6 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: repository: cloudposse-tests/argocd-deploy-non-prod-test ref: ${{ needs.test.outputs.sha }} @@ -236,7 +236,7 @@ jobs: ) echo "value=${image}" >> $GITHUB_OUTPUT - - uses: nick-fields/assert-action@v2 + - uses: nick-fields/assert-action@0efd6166067d9c59d89c710fab4f79fb066f8985 # v4.0.1 with: expected: "nginx:${{ needs.setup.outputs.random }}" actual: "${{ steps.image.outputs.value }}" @@ -251,7 +251,7 @@ jobs: ) echo "value=${ingress}" >> $GITHUB_OUTPUT - - uses: nick-fields/assert-action@v2 + - uses: nick-fields/assert-action@0efd6166067d9c59d89c710fab4f79fb066f8985 # v4.0.1 with: expected: "networking.k8s.io/v1beta1" actual: "${{ steps.ingress.outputs.value }}" @@ -266,7 +266,7 @@ jobs: ) echo "value=${name}" >> $GITHUB_OUTPUT - - uses: nick-fields/assert-action@v2 + - uses: nick-fields/assert-action@0efd6166067d9c59d89c710fab4f79fb066f8985 # v4.0.1 with: expected: "${{ needs.setup.outputs.environment }}.test-app" actual: "${{ steps.name.outputs.value }}" @@ -282,7 +282,7 @@ jobs: ) echo "value=${app_commit}" >> $GITHUB_OUTPUT - - uses: nick-fields/assert-action@v2 + - uses: nick-fields/assert-action@0efd6166067d9c59d89c710fab4f79fb066f8985 # v4.0.1 with: expected: "${{ github.sha }}" actual: "${{ steps.app_commit.outputs.value }}" diff --git a/README.md b/README.md index f6bc193..2265bfa 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,7 @@ Deploy environment operation: deploy debug: false synchronously: true + deployment-id: ${{ github.run_id }}-${{ github.run_attempt }} ``` @@ -125,9 +126,46 @@ Destroy environment ``` +### Deduping ArgoCD notifications per deploy attempt +ArgoCD's notification `oncePer` trigger dedupes on whichever field you point it at. Keying it on the +application commit means a rollback — replaying a commit ArgoCD has already notified for — is silently +suppressed, and the rollback reports no status at all. +Pass `deployment-id` a value that is unique per *deploy attempt* rather than per code state, and point +`oncePer` at it instead: +```yaml + - name: Deploy + uses: cloudposse/github-action-deploy-argocd@main + with: + # ... + deployment-id: ${{ github.run_id }}-${{ github.run_attempt }} +``` + +The value is written to the generated `config.yaml` alongside the rest of the deploy metadata: + +```yaml + app_repository: acme/example-app + app_commit: 6e6a0e1b0e0c4b2a9f1d3c5e7a9b1d3f5a7c9e1b + app_hostname: https://example-app.example.com + name: preview.example-app + namespace: preview + manifests: plat/ue2-sandbox/apps/preview/example-app/manifests + deployment_id: "12345678901-2" +``` + +The input is optional. Left at its empty default, the `deployment_id` key is omitted from `config.yaml` +entirely, so callers that do not set it get byte-identical output. + + + + + + + + + ## Inputs @@ -143,6 +181,7 @@ Destroy environment | commit-status-github-token | Github token to access the app repository. Defaults to github-pat if not set. | N/A | false | | commit-timeout | Commit timeout (in seconds) | 60 | false | | debug | Debug mode | false | false | +| deployment-id | Unique identifier for this deploy attempt (for example, the GitHub run ID joined with the run attempt). When set, it is written to `config.yaml` as `deployment\_id`, which lets ArgoCD dedupe notifications per deploy attempt instead of per commit. Left unset, the key is omitted from `config.yaml`. | | false | | environment | Helmfile environment | preview | false | | github-pat | Github PAT to access argocd configuration repository | N/A | true | | gitref-sha | Git SHA (Depricated. Use `ref` instead) | | false | diff --git a/README.yaml b/README.yaml index 705e99e..3fec7e8 100644 --- a/README.yaml +++ b/README.yaml @@ -88,6 +88,7 @@ usage: |- operation: deploy debug: false synchronously: true + deployment-id: ${{ github.run_id }}-${{ github.run_attempt }} ``` @@ -128,5 +129,38 @@ usage: |- debug: false ``` + + ### Deduping ArgoCD notifications per deploy attempt + + ArgoCD's notification `oncePer` trigger dedupes on whichever field you point it at. Keying it on the + application commit means a rollback — replaying a commit ArgoCD has already notified for — is silently + suppressed, and the rollback reports no status at all. + + Pass `deployment-id` a value that is unique per *deploy attempt* rather than per code state, and point + `oncePer` at it instead: + + ```yaml + - name: Deploy + uses: cloudposse/github-action-deploy-argocd@main + with: + # ... + deployment-id: ${{ github.run_id }}-${{ github.run_attempt }} + ``` + + The value is written to the generated `config.yaml` alongside the rest of the deploy metadata: + + ```yaml + app_repository: acme/example-app + app_commit: 6e6a0e1b0e0c4b2a9f1d3c5e7a9b1d3f5a7c9e1b + app_hostname: https://example-app.example.com + name: preview.example-app + namespace: preview + manifests: plat/ue2-sandbox/apps/preview/example-app/manifests + deployment_id: "12345678901-2" + ``` + + The input is optional. Left at its empty default, the `deployment_id` key is omitted from `config.yaml` + entirely, so callers that do not set it get byte-identical output. + include: [] contributors: [] diff --git a/action.yml b/action.yml index 46a9404..d02cf65 100644 --- a/action.yml +++ b/action.yml @@ -117,7 +117,11 @@ inputs: kube-version: description: "Kubernetes version for helm/helmfile rendering (e.g. `1.28`). When provided, skips SSM metadata lookup via chamber." required: false - default: "" + default: "" + deployment-id: + description: "Unique identifier for this deploy attempt (for example, the GitHub run ID joined with the run attempt). When set, it is written to `config.yaml` as `deployment_id`, which lets ArgoCD dedupe notifications per deploy attempt instead of per commit. Left unset, the key is omitted from `config.yaml`." + required: false + default: "" outputs: webapp-url: description: "Web Application url" @@ -206,7 +210,7 @@ runs: path: ${{ steps.destination.outputs.filepath }}/${{ inputs.namespace }}/${{ inputs.application }} - name: Checkout Argo Configuration - uses: actions/checkout@v6 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: repository: ${{ steps.destination.outputs.owner }}/${{ steps.destination.outputs.name }} ref: ${{ steps.destination.outputs.ref }} @@ -387,6 +391,15 @@ runs: namespace: ${{ inputs.namespace }} manifests: ${{ steps.config.outputs.path }}/manifests + - name: Stamp deployment id + if: ${{ inputs.operation == 'deploy' && inputs.deployment-id != '' }} + shell: bash + env: + DEPLOYMENT_ID: ${{ inputs.deployment-id }} + CONFIG_FILE: ${{ steps.config.outputs.tmp }}/config.yaml + run: |- + yq --exit-status --no-colors --inplace eval '.deployment_id = strenv(DEPLOYMENT_ID)' "${CONFIG_FILE}" + - name: Push to Github uses: nick-fields/retry@v4 id: git @@ -446,7 +459,7 @@ runs: echo "token=${{ inputs.commit-status-github-token }}" >> $GITHUB_OUTPUT fi - - uses: cloudposse/github-action-wait-commit-status@v0.2.1 + - uses: cloudposse/github-action-wait-commit-status@968fc17eddf4d9f4f2203edb4c72814a1d8bc650 # v0.2.2 if: ${{ inputs.synchronously == 'true' && inputs.operation == 'deploy' }} with: repository: ${{ inputs.repository }}