Redgate Change Automation 4

Jenkins

This example CI/CD pipeline uses the installed Redgate Change Automation command line on a Windows agent. This is implemented usinga  Pipeline as Code Jenkinsfile.  If you are familiar with Jenkinsfile, we hope you can drop this into your repository and customize the variables at the top to start a proof of concept quickly in your environment.  For a proof of concept, you can use more/less environments and you can use a permanent acceptance environment instead of provisioning it. 

Example Jenkinsfile

node {
    // Variables to set
    def ProjectPath = "[PATH_TO_CONF]" 
    def OutputDirectory = "${WORKSPACE}"
    def BuildArtifactPath = "${OutputDirectory}/build.zip"
    def ReleaseArtifactPath = "${OutputDirectory}/release.zip"
    def CiDatabaseJdbc = "jdbc:oracle:thin:@//[HOST]:[PORT]/[SERVICE NAME]"
    def AcceptanceDatabaseJdbc = "jdbc:oracle:thin:@//[HOST]:[PORT]/[SERVICE NAME]"
    def ProductionDatabaseJdbc = "jdbc:oracle:thin:@//[HOST]:[PORT]/[SERVICE NAME]"
    def Schema = "[SCHEMA NAME]"
    def User = "[USER]"				// In a real scenario, you would want to store these safely outside of this script and and pass them in
    def Password = "[PASSWORD]"		// In a real scenario, you would want to store these safely outside of this script and and pass them in
 
    stage ('Prep') {
        echo "Ensure the pipeline is configured to clean the Jenkins workspace before checkout"
        bat('set')
        deleteDir()
        checkout scm
    }
 
    stage ('Build') {
        echo "Migrating the project to a cleaned CI database; Running Code Analysis for Oracle; Checking for Invalid Objects"
         
        def status
        status = bat returnStatus: true, label: "Build", script: "rca build -P \"${ProjectPath}\" -t ${CiDatabaseJdbc} -o \"${BuildArtifactPath}\" -c -f -v -u ${User} -p ${Password} --IAgreeToTheEula"
         
        echo "Status of Running CI build: $status"
        if (status != 0) { error('Running CI build failed') }
         
        archiveArtifacts allowEmptyArchive: true, artifacts: 'build.zip'
    }
     
    stage ('Unit Tests') {
        echo "Running utPLSQL database Unit Tests"
         
        def status
        status = bat returnStatus: true, label: "Unit Tests", script: "rca test -o \"${OutputDirectory}\" -t ${CiDatabaseJdbc} -v -u ${Schema} -p ${Password} --IAgreeToTheEula"
         
        echo "Status of Running RCA test: $status"
        if (status != 0) { error('Running Unit Tests failed') }
             
        status = junit allowEmptyResults: true, testResults: 'test_results.xml'
        echo "Failed JUnit tests: $status.failCount"
        archiveArtifacts allowEmptyArchive: true, artifacts: 'test_results.xml'
 
        zip zipFile: 'code_coverage.zip', archive: true, glob: 'code_coverage.html, code_coverage.html_assets/*'
        archiveArtifacts allowEmptyArchive: true, artifacts: 'code_coverage.zip', fingerprint: true
    }
     
    stage ('Provision Acceptance') {
        echo "Provisioning a copy of the current Production database"
 
		// There are many ways to provision a copy of Production (e.g. backup/restore or using Schema Compare for Oracle and Data Compare for Oracle)
		// The example documented below is for cloning pluggable databases
		// See some additional details about this on https://documentation.red-gate.com/dso/redgate-change-automation/example-ci-cd-pipelines/Jenkins (scroll to bottom)
        def status
		status = bat returnStatus: true, label: "Drop Acceptance", script: "sqlplus -L -S ${User}/${Password}@[HOST]:[PORT]/[SERVICE NAME] as sysdba @clone-production.sql" 
		// eg sqlplus -L -S sys/${Password}@localhost:1521/orcl as sysdba @clone-production.sql
    	echo "Status of cloning Production: $status"
    	if (status != 0) { error('Cloning production failed') }
    }
     
    stage ('Prepare Release') {
        echo "Generating deployment script against Acceptance; Doing drift detection; Creating changes report"
         
        def status
        status = bat returnStatus: true, label: "Prepare Release", script: "rca release prepare -b \"${BuildArtifactPath}\" -t ${AcceptanceDatabaseJdbc} -o \"${ReleaseArtifactPath}\" -v -u ${User} -p ${Password} -f --IAgreeToTheEula"
         
        echo "Status of Prepare Release: $status"
        if (status != 0) { error('Running Prepare Release failed') }
         
        archiveArtifacts allowEmptyArchive: true, artifacts: 'release.zip'
    }
     
    stage ('Deploy to Acceptance') {
        echo "Deploying release to Acceptance database for user and performance testing"
         
        def status
        status = bat returnStatus: true, label: "Deploy to Acceptance", script: "rca release perform -r \"${ReleaseArtifactPath}\" -t ${AcceptanceDatabaseJdbc} -v -u ${User} -p ${Password} --IAgreeToTheEula"
         
        echo "Status of Deploy to Acceptance: $status"
        if (status != 0) { error('Running Deploy to Acceptance failed') }
    }
     
    stage ('Approval Gate'){
        def message = "Approve release to Production?"
 
        // wrapping in a time out so it does not block the agent and simply fails the build if there is no user intervention.
        timeout(time: 30, unit: 'MINUTES') {
            def userInput = input(
                id: 'userInput',
                message: "$message",
                parameters: [
                  [$class: 'TextParameterDefinition', defaultValue: 'I Approve The Deployment', description: 'To Proceed, type I Approve The Deployment', name: 'Review deployment artifacts before proceeding']
                ]
            )
 
            if (userInput.indexOf('I Approve The Deployment') == -1) {
                currentBuild.result = 'ABORTED'
                error('Deployment aborted')
            }
        }
    }
     
    stage ('Deploy to Production') {
        echo "Deploying release to Production database"
         
        def status
        status = bat returnStatus: true, label: "Deploy to Production", script: "rca release perform -r \"${ReleaseArtifactPath}\" -t ${ProductionDatabaseJdbc} -v -u ${User} -p ${Password} --IAgreeToTheEula"
         
        echo "Status of Deploy to Production: $status"
        if (status != 0) { error('Running Deploy to Production failed') }
    }
}

If you are using pluggable databases for the proof of concept, then you can clone your production database to provision the Acceptance database and have a realistic dry run.  Other ways to do this are by restoring a backup or using Schema Compare for Oracle to copy the schema from Production to Acceptance.  

clone-production.sql

-- Variables to set
def AcceptancePdb = <AcceptancePdbName>
def ProductionPdb = <ProductionPdbName>

-- Change your path to your Acceptance pdb file location
alter system set db_create_file_dest='C:/Oracle/oradata/ORCL/ACCEPTANCE';

alter pluggable database $(AcceptancePdb} close immediate;
drop pluggable database $(AcceptancePdb} including datafiles;

create pluggable database $(AcceptancePdb}from $(ProductionPdb};
alter pluggable database $(AcceptancePdb} open;
exit;

Didn't find what you were looking for?