Run other jobs before deployment job in stage

Viewed 241

Is it possible to run tasks/scripts within a job before a deployment job runs? I have an approval on the environment, which I want triggered by the deployment job, but it seems to want the approval before it runs job1 instead of running the tasks within job1 and then asking for approval before running the deployment job.

I want it to run all of the jobs within 'job1' and then ask for approval on the deployment job. Is this possible?

I have something similar to the below:

- stage: 1
variables:
  - group: global
jobs:
  - job: 'job1'
    steps:
      - task: DownloadPipelineArtifact@2
        ...

      - task: ExtractFiles@1
        ...

      - script: |
        ...

  - deployment:
    environment: DEV
    strategy:
      runOnce:
        deploy:
          steps:
            - script: |
                ...
2 Answers

Unfortunately, no. The pre-process step within the pipeline run expands the templates and then evaluates all the dependencies within the pipeline before the pipeline executes. For example, the runtime determines if the pipeline has permission to use variable groups + service connections, or that the person executing the pipeline is allowed to consume those resources.

It does the same thing for each stage. Prior to execution, it evaluates the dependencies within the jobs and determines if Approvals or Checks are required. It bubbles these "checks" to the Stage. It would be fairly dangerous to start a stage and get halfway through the work only to realize the stage should never been executed in the first place.

It is important to note that "deployment" is a type of "job", and each job potentially runs on different agents, so downloading the artifacts to save time (which is what appears to be happening in your example) won't work as you've illustrated.

If you want to pause the execution of the pipeline mid-execution and wait for user-interaction there is the `Manual Validation Task' which can pause and wait for a user to click continue. This doesn't enforce who's allowed to click, but it notify a set of users that the task is waiting for their involvement. It's important to call out that this task is agentless: it doesn't run in your agent pool. A good reference example would be pausing before re-enabling traffic to a website (Traffic Manager, Deployment Slot, etc).

Is it possible to run tasks/scripts within a job before a deployment job runs?

Yes

I have an approval on the environment, which I want triggered by the deployment job, but it seems to want the approval before it runs job1 instead of running the tasks within job1 and then asking for approval before running the deployment job.

If I understand correctly, you (like me) want to prepare a build and have a human interact with the pipeline to give the go-nogo to the rest of the pipeline which is the deployment to an environment.

What I do not recommend for the above scenario

If that's the case, then I have to say that you need two different pipelines.

  1. would create the build for the environment, without attaching the environment to the build. Publish this artifact
  2. Pick the artifact from No.1 and then have a deployment with the specific environment.

the environmental approval has to be done in a different pipeline where you pick up the artifact from the first build.

What I do recommend for the above scenario

The following part is using multiple stages. Dev, staging and prd. Dev environment does not need a validation but other two needs. So, in my case of dev, while on job waitForValidation I am checking if the previous build was successful and if the stage is not development. If it is, then it bypasses the job and goes directly to the nest job, deployment. In case the waitForValidation job is not bypassed, a validation is needed to continue further with the pipeline. In job deployment, there are two ifs probably out of your scope of the question but good to have in case someone else sees that in the future:

  1. If stage is development and if build job is successful, then continue with build
  2. if stage is not development and if job waitForValidation was successful then continue with build.
parameters:
  - name: 'stages'
    type: object

    default:
      - stage: Development
        dependsOn:

      - stage: Staging
        dependsOn: 'Development'

      - stage: Production
        dependsOn: 'Staging'

stages:
  - ${{each stage in parameters.stages}}:
      - stage: ${{ stage.stage }}
        dependsOn: ${{ stage.dependsOn }}
        displayName: ${{ stage.stage }}
        pool:
          vmImage: $(vmImageName)

        jobs:
          - job: Build
            displayName: Build for ${{ stage.stage }}
            steps:
              - script: |

       ... <code/steps/jobs goes here>

              - publish: $(Build.ArtifactStagingDirectory)
                artifact: '${{ stage.stage }}.$(ArtifactName)'

          - ${{ if ne(stage.stage, 'Development') }}:
              - job: waitForValidation
                displayName: 'Validation to Deploy $(ArtifactName) to ${{ stage.stage }} - $(ArtifactName), ${{variables.ArtifactName}}, and $[ ArtifactName ]'
                condition: and(succeeded(), ne('${{ stage.stage }}', 'Development'))
                dependsOn: 'Build'
                pool: server
                timeoutInMinutes: 43200 # job times out in 30 days
                steps:
                  - task: ManualValidation@0
                    timeoutInMinutes: 1 # task times out in 1 day
                    inputs:
                      notifyUsers:
                      instructions: 'Please validate the build configuration and resume'
                      onTimeout: reject

          - deployment: ${{ stage.stage }}
            displayName: Deploy to ${{ stage.stage }}
            environment: ${{ stage.stage }}
            ${{ if eq('${{ stage.stage }}', 'Development') }}:
              dependsOn: 'Build'
              condition: and(eq(dependencies.Build.result,'Succeeded'), ne(variables['Build.Reason'], 'PullRequest'))
            ${{ if ne('${{ stage.stage }}', 'Development') }}:
              dependsOn: 'waitForValidation'
              condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'))
            strategy:
              runOnce:
                deploy:
                  steps:
                    - task: Bash@3
                      inputs:
                        targetType: 'inline'
                        script: |
                          <rest of deployment>


I hope I am in par with your questions.

Related