Azure DevOps
Published 24 November 2020
This example CI/CD pipeline uses the Redgate Change Automation docker image hosted on DockerHub.
The worked example here assumes some familiarity with Azure DevOps and an Azure Pipeline set up. For instructions on how to create a pipeline visit https://docs.microsoft.com/en-gb/azure/devops/pipelines/create-first-pipeline
To set up the build pipeline, drop this example azure-pipelines.yml
file into your repository and customize the variables defined at the top.
Example azure-pipelines.yml
trigger: batch: true # Set this to ensure only one pipeline build is being run at a time. branches: include: - main # Set this to your default branch. pr: - none # This turns off builds for pull requests. pool: vmImage: "ubuntu-latest" variables: CI_DB_JDBC: "jdbc:oracle:thin:@//[HOST]:[PORT]/[SERVICE NAME]" ACCEPTANCE_DB_JDBC: "jdbc:oracle:thin:@//[HOST]:[PORT]/[SERVICE NAME]" PRODUCTION_DB_JDBC: "jdbc:oracle:thin:@//[HOST]:[PORT]/[SERVICE NAME]" RCA_IMAGE_VERSION: latest # You may want to "pin" the RCA version instead of always pulling the latest. SCHEMA: "[SCHEMA NAME]" USER: "[USER]" # In a real scenario, you would want to store these safely outside of this script and and pass them in PASSWORD: "[PASSWORD]" # In a real scenario, you would want to store these safely outside of this script and and pass them in and use different passwords for the different environments jobs: - job: Build steps: - task: Bash@3 displayName: "Running RCA build against the CI DB." inputs: targetType: 'inline' script: | echo "Migrating the project to a cleaned CI database; Running Code Analysis for Oracle; Checking for Invalid Objects" docker run --rm -v "$(Pipeline.Workspace)/s:/app/project" -v "$(Build.ArtifactStagingDirectory):/app/output" redgate/change-automation:$(RCA_IMAGE_VERSION) build -v \ -P /app/project/citi-demo.conf \ -t $(CI_DB_JDBC) \ -o /app/output/buildArtifact.zip \ -u '$(USER)' \ -p $(PASSWORD) \ --IAgreeToTheEula \ --clean - task: PublishBuildArtifacts@1 displayName: "Publish build artifact" inputs: pathToPublish: $(Build.ArtifactStagingDirectory)/buildArtifact.zip artifactName: buildArtifact - job: Test dependsOn: Build condition: succeeded('Build') steps: - task: Bash@3 displayName: "Running utPLSQL unit tests." inputs: targetType: 'inline' script: | echo "Running utPLSQL database Unit Tests" docker run --rm -v "$(Build.ArtifactStagingDirectory):/app/output" redgate/change-automation:$(RCA_IMAGE_VERSION) test -v \ -t $(CI_DB_JDBC) \ -o /app/output/testResults \ -s $(SCHEMA) \ -u '$(USER)' \ -p $(PASSWORD) \ --IAgreeToTheEula - task: PublishBuildArtifacts@1 displayName: "Publish test results" inputs: pathToPublish: $(Build.ArtifactStagingDirectory)/testResults artifactName: testResults # We require separate release prepare runs here, since we have two databases we want to release to, QA & Production, each # potentially being in a seperate state. RCA must prepare a release against the release target, reusing artifacts is not advised. - job: Prepare_Production_Release dependsOn: Test condition: succeeded('Test') steps: - task: DownloadBuildArtifacts@0 inputs: buildType: 'current' downloadType: 'single' artifactName: 'buildArtifact' downloadPath: '$(System.ArtifactsDirectory)' - task: Bash@3 displayName: "Preparing a release for Production." inputs: targetType: 'inline' script: | echo "Generating deployment script against Production; Doing drift detection; Creating changes report" docker run --rm -v "$(System.ArtifactsDirectory)/buildArtifact:/app/buildArtifact" -v "$(Build.ArtifactStagingDirectory):/app/output" redgate/change-automation:$(RCA_IMAGE_VERSION) release prepare -v \ -b /app/buildArtifact/buildArtifact.zip \ -t $(PRODUCTION_DB_JDBC) \ -o /app/output/release.zip \ -u '$(USER)' \ -p $(PASSWORD) \ -f \ --IAgreeToTheEula - task: PublishPipelineArtifact@1 inputs: targetPath: '$(Build.ArtifactStagingDirectory)/release.zip' artifact: 'production_release' publishLocation: 'pipeline' - job: Prepare_QA_Release dependsOn: Test condition: succeeded('Test') steps: - task: DownloadBuildArtifacts@0 inputs: buildType: 'current' downloadType: 'single' artifactName: 'buildArtifact' downloadPath: '$(System.ArtifactsDirectory)' - task: Bash@3 displayName: "Preparing a release for Acceptance." inputs: targetType: 'inline' script: | echo "Generating deployment script against QA; Doing drift detection; Creating changes report" docker run --rm -v "$(System.ArtifactsDirectory)/buildArtifact:/app/buildArtifact" -v "$(Build.ArtifactStagingDirectory):/app/output" redgate/change-automation:$(RCA_IMAGE_VERSION) release prepare -v \ -b /app/buildArtifact/buildArtifact.zip \ -t $(ACCEPTANCE_DB_JDBC) \ -o /app/output/release.zip \ -u '$(USER)' \ -p $(PASSWORD) \ -f \ --IAgreeToTheEula - task: PublishPipelineArtifact@1 inputs: targetPath: '$(Build.ArtifactStagingDirectory)/release.zip' artifact: 'qa_release' publishLocation: 'pipeline'
To set up the release pipeline:
- In your Azure DevOps project, click on Releases in the menu on the left and then click on New pipeline
- When prompted for a template, click on Empty job
- Specify the artifact that makes up the release pipeline. In this case, it is going to be the release artifact we publish in our build pipeline.
- Add a stage to deploy the release artifact to acceptance (for a proof of concept, you can trigger this stage automatically every time a new release artifact is available)
In the "Deploy to Acceptance" stage, add a bash task to run RCA release perform against acceptance.
Example bash script
echo "Deploying release to Acceptance database for user and performance testing" ACCEPTANCE_DB_JDBC: "jdbc:oracle:thin:@//[HOST]:[PORT]/[SERVICE NAME]" USER: "[USER]" # In a real scenario, you would want to store these safely outside of this script and and pass them in PASSWORD: "[PASSWORD]" # In a real scenario, you would want to store these safely outside of this script and and pass them in and use different passwords for the different environments RCA_IMAGE_VERSION: latest docker run --rm -v "$(System.ArtifactsDirectory)/_Redgate Change Automation CI:/app/release-artifacts" redgate/change-automation:$(RCA_IMAGE_VERSION) release perform -v \ -t $(ACCEPTANCE_DB_JDBC) \ -r "/app/release-artifacts/qa_release/release.zip" \ -o "/app/acceptance/output" \ -u $(USER) \ -p $(PASSWORD) \ --IAgreeToTheEula
- Add a final stage to deploy the release to production (hover over "Deploy to Acceptance" and click on the + button)
- For this stage, in addition to the bash task, you would want to add a task to pause the deployment and review the release before proceeding. You can do this by clicking on the pre-deployment conditions tab on the stage itself, highlighted below. Here you can set a variety of pre-conditions that need to be met before this stage is executed.