admin管理员组

文章数量:1122846

I have a workflow with several jobs which perform deployment tasks. I use matrix strategy to deploy them across multiple environments, say dev, tst and stg. So each job has strategy configured as below

    strategy:
      matrix:
        target_env: ${{ fromJson(needs.determine_target_env.outputs.target_env) }}

Also, I need someone to review deployments if the environment it is being deployed to is tst or stg (no review required for dev). I have created environments in GitHub as test-environment and stg-environment and use them as below

environment: >-
        ${{ 
          matrix.target_env == 'tst' && 'test-environment' ||
          matrix.target_env == 'stg' && 'stage-environment' ||
          ''
        }}

This triggers approvals and reviewrs can approve/reject deployment. Here is the issue with this:

  1. Since I have several jobs, it keeps asking for approvals for all of them

  2. If I move the environment to a separate job which executed first (see below), then there is no way of capturing the output of that rejection or approval, because when rejected, the workflow just fails and if I provide a continue-on-error to that job, it marks it as success even if it rejected.

      environment_approval:
        needs: determine_target_env
        runs-on: [default]
        strategy:
          matrix:
            target_env: ${{ fromJson(needs.determine_target_env.outputs.target_env) }}
          fail-fast: false
        continue-on-error: true //If this is not set, rejections marks this job as failure. If it is set, the job is always a success.
        outputs:
          approval_status: ${{ steps.check_approval.outcome }}
        environment: >-
          ${{ 
            matrix.target_env == 'tst' && 'test-environment' ||
            matrix.target_env == 'stg' && 'stage-environment' ||
            ''
          }}
        steps:
          - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
            with:
              fetch-depth: 0
          - name: Check approval status
            continue-on-error: true
            id: check_approval
            run: |
              echo "status=success" >> $GITHUB_OUTPUT
    

Is there a central way of handling deployment protection and applying it to all jobs within a workflow?

I also tried to use

  • Composite actions, which did not help as it did not support environment: context
  • Re-useable action, which is the same as using it inline

I have a workflow with several jobs which perform deployment tasks. I use matrix strategy to deploy them across multiple environments, say dev, tst and stg. So each job has strategy configured as below

    strategy:
      matrix:
        target_env: ${{ fromJson(needs.determine_target_env.outputs.target_env) }}

Also, I need someone to review deployments if the environment it is being deployed to is tst or stg (no review required for dev). I have created environments in GitHub as test-environment and stg-environment and use them as below

environment: >-
        ${{ 
          matrix.target_env == 'tst' && 'test-environment' ||
          matrix.target_env == 'stg' && 'stage-environment' ||
          ''
        }}

This triggers approvals and reviewrs can approve/reject deployment. Here is the issue with this:

  1. Since I have several jobs, it keeps asking for approvals for all of them

  2. If I move the environment to a separate job which executed first (see below), then there is no way of capturing the output of that rejection or approval, because when rejected, the workflow just fails and if I provide a continue-on-error to that job, it marks it as success even if it rejected.

      environment_approval:
        needs: determine_target_env
        runs-on: [default]
        strategy:
          matrix:
            target_env: ${{ fromJson(needs.determine_target_env.outputs.target_env) }}
          fail-fast: false
        continue-on-error: true //If this is not set, rejections marks this job as failure. If it is set, the job is always a success.
        outputs:
          approval_status: ${{ steps.check_approval.outcome }}
        environment: >-
          ${{ 
            matrix.target_env == 'tst' && 'test-environment' ||
            matrix.target_env == 'stg' && 'stage-environment' ||
            ''
          }}
        steps:
          - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
            with:
              fetch-depth: 0
          - name: Check approval status
            continue-on-error: true
            id: check_approval
            run: |
              echo "status=success" >> $GITHUB_OUTPUT
    

Is there a central way of handling deployment protection and applying it to all jobs within a workflow?

I also tried to use

  • Composite actions, which did not help as it did not support environment: context
  • Re-useable action, which is the same as using it inline
Share Improve this question asked Nov 22, 2024 at 5:00 NishNish 11 bronze badge
Add a comment  | 

2 Answers 2

Reset to default 0

my approach would be to set for every job the right 'if' condition.

As an example:

      - name: Check approval status
        if: matrix.target_env == '<env>'
        continue-on-error: true
        id: check_approval
        run: |
          echo "status=success" >> $GITHUB_OUTPUT

OK, I ended up solving it myself. I understand this is a unique case of using environments with deployment protection and then also using strategy:matrix, but here is the solution if anyone is interested .

Have another task in the same job (environment-approval)job which queries GH API deployments

Something like this

            DEPLOYMENTS_JSON=$(curl -s -H "Authorization: token ${{ steps.generate-token.outputs.token }}" \
            https://api.github.com/repos/${{ github.repository }}/deployments)

            DEPLOYMENT_ID=$(echo "$DEPLOYMENTS_JSON" | jq -r --arg DEPLOYMENT_NAME "$DEPLOYMENT_NAME" 'map(select(.environment == $DEPLOYMENT_NAME)) | sort_by(.created_at) | last | .id // empty')
            if [ -n "$DEPLOYMENT_ID" ]; then
              DEPLOYMENT_STATUS=$(curl -s -H "Authorization: token ${{ steps.generate-token.outputs.token }}" \
                https://api.github.com/repos/${{ github.repository }}/deployments/$DEPLOYMENT_ID/statuses | \
                jq -r '.[0].state') # Get the state of the most recent status

              echo "Deployment ID: $DEPLOYMENT_ID"
              echo "Deployment Status: $DEPLOYMENT_STATUS"

              if [[ "$DEPLOYMENT_STATUS" == "success" || "$DEPLOYMENT_STATUS" == "in_progress" ]]; then
                echo "approved" > ${{ matrix.target_env }}_approval_status.txt
              else
                echo "rejected" > ${{ matrix.target_env }}_approval_status.txt
              fi
            else
              echo "Deployment not found."
              exit 1
            fi

Output this into a file and have another job following this to process these files into respective environment related variable (You need another job because the latest run overrides the variable set part of strategy:matrix.

Use this new variable in all subsequent jobs to validate deployment approvals.

Hope this helps

本文标签: githubMultiple jobs and deployment protectionStack Overflow