Liquibase - Apply changeset

Octopus.Script exported 2021-02-25 by bobjwalker belongs to ‘Liquibase’ category.

Deploy database updates using Liquibase. You can include Liquibase in the package itself or choose Download to download it during runtime. Use the Report only? option to output the SQL it will run and upload it as an Artifact. NOTE: Report only? does not work with NoSQL databases such as MongoDB

This template is now deprecated, please use Liquibase - Run command

Parameters

When steps based on the template are included in a project’s deployment process, the parameters below can be set.

Pro license key

liquibaseProLicenseKey =

Enter your Liquibase Pro license key. Request a free 30-day trial. Leave blank to use the Community Edition.

Database type

liquibaseDatabaseType =

Select the database type to deploy to.

Change Log file name

liquibaseChangeLogFileName =

Name of the changelog file in the package.

Server name

liquibaseServerName =

Name or IP address of the database server.

Server port

liquibaseServerPort =

The port the database server listens on.

Database name

liquibaseDatabaseName =

Name of the database (or service name in case of Oracle) to deploy to.

Username

liquibaseUsername =

Username of a user that has permission to make changes to the database.

Password

liquibasePassword =

Password for the user with permissions to make changes to the database.

Connection query string parameters

liquibaseQueryStringParameters =

Add additional parameters to the connection string URL. Example: ?useUnicode=true

Database driver path

liquibaseClassPath =

Filepath to the location of the .jar driver for the database type.

Executable file path

liquibaseExecutablePath =

File path to the Liquibase executable.

Report only?

liquibaseReport =

This option will generate the SQL statements, save them to a file, then attach them to the step as an artifact. This option only generates the statement, it will not run them.

Download Liquibase?

liquibaseDownload =

Use this option to download the software necessary to deploy a Liquibase changeset. This will download Liquibase, java, and the appropriate driver for the selected database type. Using this option overrides the Database driver path and Executable file path inputs.

Liquibase version

liquibaseVersion =

Used with Download Liquibase to specify the version of Liquibase to use.

Changeset package

liquibaseChangeset =

Select the package with the changeset.

Script body

Steps based on this template will execute the following PowerShell script.

# Configure template

# Set TLS
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls11 -bor [System.Net.SecurityProtocolType]::Tls12

# Disable progress bar for PowerShell
$ProgressPreference = 'SilentlyContinue'

# Downloads and extracts liquibase to the work folder
Function Get-Liquibase
{
    # Define parameters
    param ($Version) 

	$repositoryName = "liquibase/liquibase"

    # Check to see if version wasn't specified
    if ([string]::IsNullOrEmpty($Version))
    {
        # Get the latest version download url
        $downloadUrl = (Get-LatestVersionDownloadUrl -Repository $repositoryName | Where-Object {$_.EndsWith(".zip")})
    }
    else
    {
    	$downloadUrl = (Get-LatestVersionDownloadUrl -Repository $repositoryName -Version $Version | Where-Object {$_.EndsWith(".zip")})
    }

    # Check for download folder
    if ((Test-Path -Path "$PSSCriptRoot\liquibase") -eq $false)
    {
        # Create the folder
        New-Item -ItemType Directory -Path "$PSSCriptRoot\liquibase"
    }

    # Download the zip file
    Write-Output "Downloading Liquibase from $downloadUrl ..."
    $liquibaseZipFile = "$PSScriptroot\liquibase\$($downloadUrl.Substring($downloadUrl.LastIndexOf("/")))"
    Invoke-WebRequest -Uri $downloadUrl -OutFile $liquibaseZipFile -UseBasicParsing
    

    # Extract package
    Write-Output "Extracting Liqbuibase ..."
    Expand-Archive -Path $liquibaseZipFile -DestinationPath "$PSSCriptRoot\liquibase"
}

# Downloads and extracts Java to the work folder, then adds the location of java.exe to the $env:PATH variabble so it can be called
Function Get-Java
{
    # Check to see if a folder needs to be created
    if((Test-Path -Path "$PSScriptRoot\jdk") -eq $false)
    {
        # Create new folder
        New-Item -ItemType Directory -Path "$PSSCriptRoot\jdk"
    }

    # Download java
    Write-Output "Downloading Java ... "
    Invoke-WebRequest -Uri "https://download.java.net/java/GA/jdk14.0.2/205943a0976c4ed48cb16f1043c5c647/12/GPL/openjdk-14.0.2_windows-x64_bin.zip" -OutFile "$PSScriptroot\jdk\openjdk-14.0.2_windows-x64_bin.zip" -UseBasicParsing

    # Extract
    Write-Output "Extracting Java ... "
    Expand-Archive -Path "$PSScriptroot\jdk\openjdk-14.0.2_windows-x64_bin.zip" -DestinationPath "$PSSCriptRoot\jdk"

    # Get Java executable
    $javaExecutable = Get-ChildItem -Path "$PSScriptRoot\jdk" -Recurse | Where-Object {$_.Name -eq "java.exe"}

    # Add path to current session
    $env:PATH += ";$($javaExecutable.Directory)"
}

# Gets download url of latest release with an asset
Function Get-LatestVersionDownloadUrl
{
    # Define parameters
    param(
    	$Repository,
        $Version
    )
    
    # Define local variables
    $releases = "https://api.github.com/repos/$Repository/releases"
    
    # Get latest version
    Write-Host "Determining latest release ..."
    
    $tags = (Invoke-WebRequest $releases -UseBasicParsing | ConvertFrom-Json)
    
    if ($null -ne $Version)
    {
    	$tags = ($tags | Where-Object {$_.name.EndsWith($Version)})
    }

    # Find the latest version with a downloadable asset
    foreach ($tag in $tags)
    {
        if ($tag.assets.Count -gt 0)
        {
            return $tag.assets.browser_download_url
        }
    }

    # Return the version
    return $null
}

# Finds the specified changelog file
Function Get-ChangeLog
{
    # Define parameters
    param ($FileName)
    
    # Find file
    $fileReference = (Get-ChildItem -Path $OctopusParameters["Octopus.Action.Package[liquibaseChangeSet].ExtractedPath"] -Recurse | Where-Object {$_.Name -eq $FileName})

    # Check to see if something weas returned
    if ($null -eq $fileReference)
    {
        # Not found
        Write-Error "$FileName was not found in $PSScriptRoot or subfolders."
    }

    # Return the reference
    return $fileReference
}

# Downloads the appropriate JDBC driver
Function Get-DatabaseJar
{
    # Define parameters
    param ($DatabaseType)

    # Declare local variables
    $driverPath = ""

    # Check to see if a folder needs to be created
    if((Test-Path -Path "$PSScriptRoot\DatabaseDriver") -eq $false)
    {
        # Create new folder
        New-Item -ItemType Directory -Path "$PSSCriptRoot\DatabaseDriver" | Out-Null
    }

    # Download the driver for the selected type
    switch ($DatabaseType)
    {
        "MariaDB"
        {
            # Download MariaDB driver
            Write-Host "Downloading MariaDB driver ..."
            $driverPath = "$PSScriptroot\DatabaseDriver\mariadb-java-client-2.6.2.jar"
            Invoke-WebRequest -Uri "https://downloads.mariadb.com/Connectors/java/connector-java-2.6.2/mariadb-java-client-2.6.2.jar" -OutFile $driverPath -UseBasicParsing
             
            break
        }
        "MongoDB"
        {
        	# Set repo name
            $repositoryName = "liquibase/liquibase-mongodb"
            
            # Download MongoDB driver
            Write-Host "Downloading Maven MongoDB driver ..."
            $driverPath = "$PSScriptroot\DatabaseDriver\mongo-java-driver-3.12.7.jar"
            Invoke-WebRequest -Uri "https://repo1.maven.org/maven2/org/mongodb/mongo-java-driver/3.12.7/mongo-java-driver-3.12.7.jar" -Outfile $driverPath -UseBasicParsing
            
            if ([string]::IsNullOrEmpty($liquibaseVersion))
            {
            	# Get the latest version for the extension
            	$downloadUrl = (Get-LatestVersionDownloadUrl -Repository $repositoryName | Where-Object {$_.EndsWith(".jar")})
           	}
            else
            {
            	# Download version matching extension
                $downloadUrl = (Get-LatestVersionDownloadUrl -Repository $repositoryName -Version $liquibaseVersion | Where-Object {$_.EndsWith(".jar")})
            }
                        
			Write-Host "Downloading MongoDB Liquibase extension from $downloadUrl ..."
            $extensionPath = "$PSScriptroot\$($downloadUrl.Substring($downloadUrl.LastIndexOf("/")))"
            
            Invoke-WebRequest -Uri $downloadUrl -Outfile $extensionPath -UseBasicParsing
                        
            # Make driver path null
            $driverPath = "$driverPath;$extensionPath"
            
            break
        }
        "MySQL"
        {
            # Download MariaDB driver
            Write-Host "Downloading MySQL driver ..."
            Invoke-WebRequest -Uri "https://dev.mysql.com/get/Downloads/Connector-J/mysql-connector-java-8.0.21.zip" -OutFile "$PSScriptroot\DatabaseDriver\mysql-connector-java-8.0.21.zip" -UseBasicParsing

            # Extract package
            Write-Host "Extracting MySQL driver ..."
            Expand-Archive -Path "$PSScriptroot\DatabaseDriver\mysql-connector-java-8.0.21.zip" -DestinationPath "$PSSCriptRoot\DatabaseDriver"

            # Find driver
            $driverPath = (Get-ChildItem -Path "$PSScriptRoot\DatabaseDriver" -Recurse | Where-Object {$_.Name -eq "mysql-connector-java-8.0.21.jar"}).FullName

            break
        }
        "Oracle"
        {
            # Download Oracle driver
            Write-Host "Downloading Oracle driver ..."
            $driverPath = "$PSScriptroot\DatabaseDriver\ojdbc10.jar"
            Invoke-WebRequest -Uri "https://download.oracle.com/otn-pub/otn_software/jdbc/211/ojdbc11.jar" -OutFile $driverPath -UseBasicParsing

            break
        }
        "SqlServer"
        {
            # Download Microsoft driver
            Write-Host "Downloading Sql Server driver ..."
            Invoke-WebRequest -Uri "https://go.microsoft.com/fwlink/?linkid=2137600" -OutFile "$PSScriptroot\DatabaseDriver\sqljdbc_8.4.0.0_enu.zip" -UseBasicParsing

            # Extract package
            Write-Host "Extracting SqlServer driver ..."
            Expand-Archive -Path "$PSScriptroot\DatabaseDriver\sqljdbc_8.4.0.0_enu.zip" -DestinationPath "$PSSCriptRoot\DatabaseDriver"

            # Find driver
            $driverPath = (Get-ChildItem -Path "$PSSCriptRoot\DatabaseDriver" -Recurse | Where-Object {$_.Name -eq "mssql-jdbc-8.4.1.jre14.jar"}).FullName

			break
        }
        "PostgreSQL"
        {
            # Download PostgreSQL driver
            Write-Host "Downloading PostgreSQL driver ..."
            $driverPath = "$PSScriptroot\DatabaseDriver\postgresql-42.2.12.jar"
            Invoke-WebRequest -Uri "https://jdbc.postgresql.org/download/postgresql-42.2.12.jar" -OutFile $driverPath -UseBasicParsing

            break
        }
        default
        {
            # Display error
            Write-Error "Unknown database type: $DatabaseType."
        }
    }

    # Return the driver location
    return $driverPath
}

# Returns the driver name for the liquibase call
Function Get-DatabaseDriverName
{
    # Define parameters
    param ($DatabaseType)

    # Declare local variables
    $driverName = ""

    # Download the driver for the selected type
    switch ($DatabaseType)
    {
        "MariaDB"
        {
            $driverName = "org.mariadb.jdbc.Driver"
            break
        }
        "MongoDB"
        {
        	$driverName = $null
            break
        }
        "MySQL"
        {
            $driverName = "com.mysql.cj.jdbc.Driver"
            break
        }
        "Oracle"
        {
            $driverName = "oracle.jdbc.OracleDriver"
            break
        }
        "SqlServer"
        {
            $driverName = "com.microsoft.sqlserver.jdbc.SQLServerDriver"
            break
        }
        "PostgreSQL"
        {
            $driverName = "org.postgresql.Driver"
            break
        }
        default
        {
            # Display error
            Write-Error "Unkonwn database type: $DatabaseType."
        }
    }

    # Return the driver location
    return $driverName
}

# Returns the connection string formatted for the database type
Function Get-ConnectionUrl
{
    # Define parameters
    param ($DatabaseType, 
    	$ServerPort, 
        $ServerName, 
        $DatabaseName, 
        $QueryStringParameters)

    # Define local variables
    $connectioUrl = ""

    # Download the driver for the selected type
    switch ($DatabaseType)
    {
        "MariaDB"
        {
            $connectionUrl = "jdbc:mariadb://{0}:{1}/{2}"
            break
        }
        "MongoDB"
        {
        	$connectionUrl = "mongodb://{0}:{1}/{2}"            
            break
        }
        "MySQL"
        {
            $connectionUrl = "jdbc:mysql://{0}:{1}/{2}"
            break
        }
        "Oracle"
        {
            $connectionUrl = "jdbc:oracle:thin:@{0}:{1}:{2}"
            break
        }
        "SqlServer"
        {
            $connectionUrl = "jdbc:sqlserver://{0}:{1};database={2};"
            break
        }
        "PostgreSQL"
        {
            $connectionUrl = "jdbc:postgresql://{0}:{1}/{2}"
            break
        }
        default
        {
            # Display error
            Write-Error "Unkonwn database type: $DatabaseType."
        }
    }

    if (![string]::IsNullOrEmpty($QueryStringParameters))
    {
        if ($QueryStringParameters.StartsWith("?") -eq $false)
        {
            # Add the question mark
            $connectionUrl += "?"
        }
        $connectionUrl += "$QueryStringParameters"
    }

    # Return the url
    return ($connectionUrl -f $ServerName, $ServerPort, $DatabaseName)
}

# Create array for arguments
$liquibaseArguments = @()

# Check for license key
if (![string]::IsNullOrEmpty($liquibaseProLicenseKey))
{
	# Add key to arguments
    $liquibaseArguments += "--liquibaseProLicenseKey=$liquibaseProLicenseKey"
}

# Find Change log
$changeLogFile = (Get-ChangeLog -FileName $liquibaseChangeLogFileName)
$liquibaseArguments += "--changeLogFile=$($changeLogFile.Name)"

# Check to see if it needs to be downloaed to machine
if ($liquibaseDownload -eq $true)
{
    # Download and extract liquibase
    Get-Liquibase -Version $liquibaseVersion -DownloadFolder $workingFolder

    # Download and extract java and add it to PATH environment variable
    Get-Java

    # Get the driver
    $driverPath = Get-DatabaseJar -DatabaseType $liquibaseDatabaseType

	if (![string]::IsNullOrEmpty($driverPath))
    {
    	# Add to arguments
    	$liquibaseArguments += "--classpath=$driverPath"
    }
}
else
{
    if (![string]::IsNullOrEmpty($liquibaseClassPath))
    {
    	$liquibaseArguments += "--classpath=$liquibaseClassPath"
    }
}

# Check to see if liquibase path has been defined
if ([string]::IsNullOrEmpty($liquibaseExecutablePath))
{
    # Assign root
    $liquibaseExecutablePath = $PSSCriptRoot
}

# Get the executable location
$liquibaseExecutable = Get-ChildItem -Path $liquibaseExecutablePath -Recurse | Where-Object {$_.Name -eq "liquibase.bat"}

# Add path to current session
$env:PATH += ";$($liquibaseExecutable.Directory)"

# Check to make sure it was found
if ([string]::IsNullOrEmpty($liquibaseExecutable))
{
    # Could not find the executable
    Write-Error "Unable to find liquibase.bat in $PSScriptRoot or subfolders."
}

# Add argument for driver
#$databaseDriver = Get-DatabaseDriverName -DatabaseType $liquibaseDatabaseType
#if (![string]::IsNullOrEmpty($databaseDriver))
#{
#	$liquibaseArguments += "--driver=$databaseDriver"
#}

# Add connection Url
$connectionUrl = Get-ConnectionUrl -DatabaseType $liquibaseDatabaseType -ServerPort $liquibaseServerPort -ServerName $liquibaseServerName -DatabaseName $liquibaseDatabaseName -QueryStringParameters $liquibaseQueryStringParameters
$liquibaseArguments += "--url=$connectionUrl"

# Add Username and password
$liquibaseArguments += "--username=$liquibaseUsername"
$liquibaseArguments += "--password=`"$liquibasePassword`""

# Set the location to where the file is
Set-Location -Path $changeLogFile.Directory

# Check to see if it should run or just report
if ($liquibaseReport -eq $true)
{
    # Set error action preference - updateSQL writes to stderr so this is to prevent errors from showing up
    $ErrorActionPreference = "SilentlyContinue"
    
    # Add just report
    $liquibaseArguments += "updateSQL"
    
    # Execute liquibase
    $liquibaseProcess = Start-Process -FilePath $liquibaseExecutable.FullName -ArgumentList $liquibaseArguments -RedirectStandardError "$PSScriptRoot\stderr.txt" -RedirectStandardOutput "$PSScriptRoot\ChangeSet.sql" -Passthru -Wait
	    
    # Display standard error
    foreach ($line in (Get-Content -Path "$PSScriptRoot\stderr.txt"))
    {
    	# Display
        Write-Host "$line"
    }
    
    # Check exit code
    if ($liquibaseProcess.ExitCode -eq 0)
    {
    	# Attach artifact
        New-OctopusArtifact -Path "$PSScriptRoot\ChangeSet.sql" -Name "ChangeSet.sql"
    }
}
else
{
    $liquibaseArguments += "update"
    & $liquibaseExecutable.FullName $liquibaseArguments
}


Provided under the Apache License version 2.0.

Report an issue

To use this template in Octopus Deploy, copy the JSON below and paste it into the Library → Step templates → Import dialog.

{
  "Id": "6a276a58-d082-425f-a77a-ff7b3979ce2e",
  "Name": "Liquibase - Apply changeset",
  "Description": "Deploy database updates using Liquibase.  You can include Liquibase in the package itself or choose Download to download it during runtime.  Use the `Report only?` option to output the SQL it will run and upload it as an Artifact.  NOTE: `Report only?` does not work with NoSQL databases such as MongoDB \n\n**This template is now deprecated, please use `Liquibase - Run command`**",
  "Version": 13,
  "ExportedAt": "2021-02-25T23:33:12.871Z",
  "ActionType": "Octopus.Script",
  "Author": "bobjwalker",
  "Packages": [
    {
      "PackageId": null,
      "FeedId": null,
      "AcquisitionLocation": "Server",
      "Properties": {
        "Extract": "True",
        "SelectionMode": "deferred",
        "PackageParameterName": "liquibaseChangeset"
      },
      "Id": "15eeeac8-d80d-46ba-bc52-413fddae36f3",
      "Name": "liquibaseChangeset"
    }
  ],
  "Parameters": [
    {
      "Id": "38e92902-4a82-41f3-a86a-3e467da0c454",
      "Name": "liquibaseProLicenseKey",
      "Label": "Pro license key",
      "HelpText": "Enter your Liquibase Pro license key. [Request a free 30-day trial.](https://www.liquibase.com/trial) Leave blank to use the Community Edition.",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Id": "4477651b-2b6d-4352-a1bd-9b9e46c31c75",
      "Name": "liquibaseDatabaseType",
      "Label": "Database type",
      "HelpText": "Select the database type to deploy to.",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "Select",
        "Octopus.SelectOptions": "MariaDB|MariaDB\nMongoDB|MongoDB\nMySQL|MySQL\nOracle|Oracle\nPostgreSQL|PostgreSQL\nSqlServer|SqlServer"
      }
    },
    {
      "Id": "4c738f97-c803-4a14-895e-ad6bacf09270",
      "Name": "liquibaseChangeLogFileName",
      "Label": "Change Log file name",
      "HelpText": "Name of the changelog file in the package.",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Id": "25ee8ea4-f38b-42e6-a503-026d72cc83a2",
      "Name": "liquibaseServerName",
      "Label": "Server name",
      "HelpText": "Name or IP address of the database server.",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Id": "592c5987-394a-41c2-bd82-1e234e470296",
      "Name": "liquibaseServerPort",
      "Label": "Server port",
      "HelpText": "The port the database server listens on.",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Id": "8e43ac61-4623-4102-bb59-58a2571bfa42",
      "Name": "liquibaseDatabaseName",
      "Label": "Database name",
      "HelpText": "Name of the database (or service name in case of Oracle) to deploy to.",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Id": "93f218a0-8fb3-42ab-bcb9-500d9f68922b",
      "Name": "liquibaseUsername",
      "Label": "Username",
      "HelpText": "Username of a user that has permission to make changes to the database.",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Id": "a2d1fee4-7161-4f8c-8d81-c00780acb79e",
      "Name": "liquibasePassword",
      "Label": "Password",
      "HelpText": "Password for the user with permissions to make changes to the database.",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "Sensitive"
      }
    },
    {
      "Id": "42741eb0-3768-4b99-8ad2-668b92db0c77",
      "Name": "liquibaseQueryStringParameters",
      "Label": "Connection query string parameters",
      "HelpText": "Add additional parameters to the connection string URL. Example: ?useUnicode=true",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Id": "1d907292-d8c6-4afc-bc26-34125b1f66ec",
      "Name": "liquibaseClassPath",
      "Label": "Database driver path",
      "HelpText": "Filepath to the location of the .jar driver for the database type.",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Id": "49c3a944-b727-4487-b2b1-493527177f5d",
      "Name": "liquibaseExecutablePath",
      "Label": "Executable file path",
      "HelpText": "File path to the Liquibase executable.",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Id": "6e2c9b48-9e67-4bed-aafa-3dc5257f9f62",
      "Name": "liquibaseReport",
      "Label": "Report only?",
      "HelpText": "This option will generate the SQL statements, save them to a file, then attach them to the step as an artifact.  This option only generates the statement, it will not run them.",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "Checkbox"
      }
    },
    {
      "Id": "35500312-a25b-4a05-ac1e-68a7f51afd1e",
      "Name": "liquibaseDownload",
      "Label": "Download Liquibase?",
      "HelpText": "Use this option to download the software necessary to deploy a Liquibase changeset.  This will download Liquibase, java, and the appropriate driver for the selected database type.  Using this option overrides the `Database driver path` and `Executable file path` inputs.",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "Checkbox"
      }
    },
    {
      "Id": "3602d6ce-94af-4d59-acc9-ae8a84bafd01",
      "Name": "liquibaseVersion",
      "Label": "Liquibase version",
      "HelpText": "Used with `Download Liquibase` to specify the version of Liquibase to use.",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Id": "235f6187-0fbf-409a-820f-61d81cea3722",
      "Name": "liquibaseChangeset",
      "Label": "Changeset package",
      "HelpText": "Select the package with the changeset.",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "Package"
      }
    }
  ],
  "Properties": {
    "Octopus.Action.Script.ScriptSource": "Inline",
    "Octopus.Action.Script.Syntax": "PowerShell",
    "Octopus.Action.Script.ScriptBody": "# Configure template\n\n# Set TLS\n[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls11 -bor [System.Net.SecurityProtocolType]::Tls12\n\n# Disable progress bar for PowerShell\n$ProgressPreference = 'SilentlyContinue'\n\n# Downloads and extracts liquibase to the work folder\nFunction Get-Liquibase\n{\n    # Define parameters\n    param ($Version) \n\n\t$repositoryName = \"liquibase/liquibase\"\n\n    # Check to see if version wasn't specified\n    if ([string]::IsNullOrEmpty($Version))\n    {\n        # Get the latest version download url\n        $downloadUrl = (Get-LatestVersionDownloadUrl -Repository $repositoryName | Where-Object {$_.EndsWith(\".zip\")})\n    }\n    else\n    {\n    \t$downloadUrl = (Get-LatestVersionDownloadUrl -Repository $repositoryName -Version $Version | Where-Object {$_.EndsWith(\".zip\")})\n    }\n\n    # Check for download folder\n    if ((Test-Path -Path \"$PSSCriptRoot\\liquibase\") -eq $false)\n    {\n        # Create the folder\n        New-Item -ItemType Directory -Path \"$PSSCriptRoot\\liquibase\"\n    }\n\n    # Download the zip file\n    Write-Output \"Downloading Liquibase from $downloadUrl ...\"\n    $liquibaseZipFile = \"$PSScriptroot\\liquibase\\$($downloadUrl.Substring($downloadUrl.LastIndexOf(\"/\")))\"\n    Invoke-WebRequest -Uri $downloadUrl -OutFile $liquibaseZipFile -UseBasicParsing\n    \n\n    # Extract package\n    Write-Output \"Extracting Liqbuibase ...\"\n    Expand-Archive -Path $liquibaseZipFile -DestinationPath \"$PSSCriptRoot\\liquibase\"\n}\n\n# Downloads and extracts Java to the work folder, then adds the location of java.exe to the $env:PATH variabble so it can be called\nFunction Get-Java\n{\n    # Check to see if a folder needs to be created\n    if((Test-Path -Path \"$PSScriptRoot\\jdk\") -eq $false)\n    {\n        # Create new folder\n        New-Item -ItemType Directory -Path \"$PSSCriptRoot\\jdk\"\n    }\n\n    # Download java\n    Write-Output \"Downloading Java ... \"\n    Invoke-WebRequest -Uri \"https://download.java.net/java/GA/jdk14.0.2/205943a0976c4ed48cb16f1043c5c647/12/GPL/openjdk-14.0.2_windows-x64_bin.zip\" -OutFile \"$PSScriptroot\\jdk\\openjdk-14.0.2_windows-x64_bin.zip\" -UseBasicParsing\n\n    # Extract\n    Write-Output \"Extracting Java ... \"\n    Expand-Archive -Path \"$PSScriptroot\\jdk\\openjdk-14.0.2_windows-x64_bin.zip\" -DestinationPath \"$PSSCriptRoot\\jdk\"\n\n    # Get Java executable\n    $javaExecutable = Get-ChildItem -Path \"$PSScriptRoot\\jdk\" -Recurse | Where-Object {$_.Name -eq \"java.exe\"}\n\n    # Add path to current session\n    $env:PATH += \";$($javaExecutable.Directory)\"\n}\n\n# Gets download url of latest release with an asset\nFunction Get-LatestVersionDownloadUrl\n{\n    # Define parameters\n    param(\n    \t$Repository,\n        $Version\n    )\n    \n    # Define local variables\n    $releases = \"https://api.github.com/repos/$Repository/releases\"\n    \n    # Get latest version\n    Write-Host \"Determining latest release ...\"\n    \n    $tags = (Invoke-WebRequest $releases -UseBasicParsing | ConvertFrom-Json)\n    \n    if ($null -ne $Version)\n    {\n    \t$tags = ($tags | Where-Object {$_.name.EndsWith($Version)})\n    }\n\n    # Find the latest version with a downloadable asset\n    foreach ($tag in $tags)\n    {\n        if ($tag.assets.Count -gt 0)\n        {\n            return $tag.assets.browser_download_url\n        }\n    }\n\n    # Return the version\n    return $null\n}\n\n# Finds the specified changelog file\nFunction Get-ChangeLog\n{\n    # Define parameters\n    param ($FileName)\n    \n    # Find file\n    $fileReference = (Get-ChildItem -Path $OctopusParameters[\"Octopus.Action.Package[liquibaseChangeSet].ExtractedPath\"] -Recurse | Where-Object {$_.Name -eq $FileName})\n\n    # Check to see if something weas returned\n    if ($null -eq $fileReference)\n    {\n        # Not found\n        Write-Error \"$FileName was not found in $PSScriptRoot or subfolders.\"\n    }\n\n    # Return the reference\n    return $fileReference\n}\n\n# Downloads the appropriate JDBC driver\nFunction Get-DatabaseJar\n{\n    # Define parameters\n    param ($DatabaseType)\n\n    # Declare local variables\n    $driverPath = \"\"\n\n    # Check to see if a folder needs to be created\n    if((Test-Path -Path \"$PSScriptRoot\\DatabaseDriver\") -eq $false)\n    {\n        # Create new folder\n        New-Item -ItemType Directory -Path \"$PSSCriptRoot\\DatabaseDriver\" | Out-Null\n    }\n\n    # Download the driver for the selected type\n    switch ($DatabaseType)\n    {\n        \"MariaDB\"\n        {\n            # Download MariaDB driver\n            Write-Host \"Downloading MariaDB driver ...\"\n            $driverPath = \"$PSScriptroot\\DatabaseDriver\\mariadb-java-client-2.6.2.jar\"\n            Invoke-WebRequest -Uri \"https://downloads.mariadb.com/Connectors/java/connector-java-2.6.2/mariadb-java-client-2.6.2.jar\" -OutFile $driverPath -UseBasicParsing\n             \n            break\n        }\n        \"MongoDB\"\n        {\n        \t# Set repo name\n            $repositoryName = \"liquibase/liquibase-mongodb\"\n            \n            # Download MongoDB driver\n            Write-Host \"Downloading Maven MongoDB driver ...\"\n            $driverPath = \"$PSScriptroot\\DatabaseDriver\\mongo-java-driver-3.12.7.jar\"\n            Invoke-WebRequest -Uri \"https://repo1.maven.org/maven2/org/mongodb/mongo-java-driver/3.12.7/mongo-java-driver-3.12.7.jar\" -Outfile $driverPath -UseBasicParsing\n            \n            if ([string]::IsNullOrEmpty($liquibaseVersion))\n            {\n            \t# Get the latest version for the extension\n            \t$downloadUrl = (Get-LatestVersionDownloadUrl -Repository $repositoryName | Where-Object {$_.EndsWith(\".jar\")})\n           \t}\n            else\n            {\n            \t# Download version matching extension\n                $downloadUrl = (Get-LatestVersionDownloadUrl -Repository $repositoryName -Version $liquibaseVersion | Where-Object {$_.EndsWith(\".jar\")})\n            }\n                        \n\t\t\tWrite-Host \"Downloading MongoDB Liquibase extension from $downloadUrl ...\"\n            $extensionPath = \"$PSScriptroot\\$($downloadUrl.Substring($downloadUrl.LastIndexOf(\"/\")))\"\n            \n            Invoke-WebRequest -Uri $downloadUrl -Outfile $extensionPath -UseBasicParsing\n                        \n            # Make driver path null\n            $driverPath = \"$driverPath;$extensionPath\"\n            \n            break\n        }\n        \"MySQL\"\n        {\n            # Download MariaDB driver\n            Write-Host \"Downloading MySQL driver ...\"\n            Invoke-WebRequest -Uri \"https://dev.mysql.com/get/Downloads/Connector-J/mysql-connector-java-8.0.21.zip\" -OutFile \"$PSScriptroot\\DatabaseDriver\\mysql-connector-java-8.0.21.zip\" -UseBasicParsing\n\n            # Extract package\n            Write-Host \"Extracting MySQL driver ...\"\n            Expand-Archive -Path \"$PSScriptroot\\DatabaseDriver\\mysql-connector-java-8.0.21.zip\" -DestinationPath \"$PSSCriptRoot\\DatabaseDriver\"\n\n            # Find driver\n            $driverPath = (Get-ChildItem -Path \"$PSScriptRoot\\DatabaseDriver\" -Recurse | Where-Object {$_.Name -eq \"mysql-connector-java-8.0.21.jar\"}).FullName\n\n            break\n        }\n        \"Oracle\"\n        {\n            # Download Oracle driver\n            Write-Host \"Downloading Oracle driver ...\"\n            $driverPath = \"$PSScriptroot\\DatabaseDriver\\ojdbc10.jar\"\n            Invoke-WebRequest -Uri \"https://download.oracle.com/otn-pub/otn_software/jdbc/211/ojdbc11.jar\" -OutFile $driverPath -UseBasicParsing\n\n            break\n        }\n        \"SqlServer\"\n        {\n            # Download Microsoft driver\n            Write-Host \"Downloading Sql Server driver ...\"\n            Invoke-WebRequest -Uri \"https://go.microsoft.com/fwlink/?linkid=2137600\" -OutFile \"$PSScriptroot\\DatabaseDriver\\sqljdbc_8.4.0.0_enu.zip\" -UseBasicParsing\n\n            # Extract package\n            Write-Host \"Extracting SqlServer driver ...\"\n            Expand-Archive -Path \"$PSScriptroot\\DatabaseDriver\\sqljdbc_8.4.0.0_enu.zip\" -DestinationPath \"$PSSCriptRoot\\DatabaseDriver\"\n\n            # Find driver\n            $driverPath = (Get-ChildItem -Path \"$PSSCriptRoot\\DatabaseDriver\" -Recurse | Where-Object {$_.Name -eq \"mssql-jdbc-8.4.1.jre14.jar\"}).FullName\n\n\t\t\tbreak\n        }\n        \"PostgreSQL\"\n        {\n            # Download PostgreSQL driver\n            Write-Host \"Downloading PostgreSQL driver ...\"\n            $driverPath = \"$PSScriptroot\\DatabaseDriver\\postgresql-42.2.12.jar\"\n            Invoke-WebRequest -Uri \"https://jdbc.postgresql.org/download/postgresql-42.2.12.jar\" -OutFile $driverPath -UseBasicParsing\n\n            break\n        }\n        default\n        {\n            # Display error\n            Write-Error \"Unknown database type: $DatabaseType.\"\n        }\n    }\n\n    # Return the driver location\n    return $driverPath\n}\n\n# Returns the driver name for the liquibase call\nFunction Get-DatabaseDriverName\n{\n    # Define parameters\n    param ($DatabaseType)\n\n    # Declare local variables\n    $driverName = \"\"\n\n    # Download the driver for the selected type\n    switch ($DatabaseType)\n    {\n        \"MariaDB\"\n        {\n            $driverName = \"org.mariadb.jdbc.Driver\"\n            break\n        }\n        \"MongoDB\"\n        {\n        \t$driverName = $null\n            break\n        }\n        \"MySQL\"\n        {\n            $driverName = \"com.mysql.cj.jdbc.Driver\"\n            break\n        }\n        \"Oracle\"\n        {\n            $driverName = \"oracle.jdbc.OracleDriver\"\n            break\n        }\n        \"SqlServer\"\n        {\n            $driverName = \"com.microsoft.sqlserver.jdbc.SQLServerDriver\"\n            break\n        }\n        \"PostgreSQL\"\n        {\n            $driverName = \"org.postgresql.Driver\"\n            break\n        }\n        default\n        {\n            # Display error\n            Write-Error \"Unkonwn database type: $DatabaseType.\"\n        }\n    }\n\n    # Return the driver location\n    return $driverName\n}\n\n# Returns the connection string formatted for the database type\nFunction Get-ConnectionUrl\n{\n    # Define parameters\n    param ($DatabaseType, \n    \t$ServerPort, \n        $ServerName, \n        $DatabaseName, \n        $QueryStringParameters)\n\n    # Define local variables\n    $connectioUrl = \"\"\n\n    # Download the driver for the selected type\n    switch ($DatabaseType)\n    {\n        \"MariaDB\"\n        {\n            $connectionUrl = \"jdbc:mariadb://{0}:{1}/{2}\"\n            break\n        }\n        \"MongoDB\"\n        {\n        \t$connectionUrl = \"mongodb://{0}:{1}/{2}\"            \n            break\n        }\n        \"MySQL\"\n        {\n            $connectionUrl = \"jdbc:mysql://{0}:{1}/{2}\"\n            break\n        }\n        \"Oracle\"\n        {\n            $connectionUrl = \"jdbc:oracle:thin:@{0}:{1}:{2}\"\n            break\n        }\n        \"SqlServer\"\n        {\n            $connectionUrl = \"jdbc:sqlserver://{0}:{1};database={2};\"\n            break\n        }\n        \"PostgreSQL\"\n        {\n            $connectionUrl = \"jdbc:postgresql://{0}:{1}/{2}\"\n            break\n        }\n        default\n        {\n            # Display error\n            Write-Error \"Unkonwn database type: $DatabaseType.\"\n        }\n    }\n\n    if (![string]::IsNullOrEmpty($QueryStringParameters))\n    {\n        if ($QueryStringParameters.StartsWith(\"?\") -eq $false)\n        {\n            # Add the question mark\n            $connectionUrl += \"?\"\n        }\n        $connectionUrl += \"$QueryStringParameters\"\n    }\n\n    # Return the url\n    return ($connectionUrl -f $ServerName, $ServerPort, $DatabaseName)\n}\n\n# Create array for arguments\n$liquibaseArguments = @()\n\n# Check for license key\nif (![string]::IsNullOrEmpty($liquibaseProLicenseKey))\n{\n\t# Add key to arguments\n    $liquibaseArguments += \"--liquibaseProLicenseKey=$liquibaseProLicenseKey\"\n}\n\n# Find Change log\n$changeLogFile = (Get-ChangeLog -FileName $liquibaseChangeLogFileName)\n$liquibaseArguments += \"--changeLogFile=$($changeLogFile.Name)\"\n\n# Check to see if it needs to be downloaed to machine\nif ($liquibaseDownload -eq $true)\n{\n    # Download and extract liquibase\n    Get-Liquibase -Version $liquibaseVersion -DownloadFolder $workingFolder\n\n    # Download and extract java and add it to PATH environment variable\n    Get-Java\n\n    # Get the driver\n    $driverPath = Get-DatabaseJar -DatabaseType $liquibaseDatabaseType\n\n\tif (![string]::IsNullOrEmpty($driverPath))\n    {\n    \t# Add to arguments\n    \t$liquibaseArguments += \"--classpath=$driverPath\"\n    }\n}\nelse\n{\n    if (![string]::IsNullOrEmpty($liquibaseClassPath))\n    {\n    \t$liquibaseArguments += \"--classpath=$liquibaseClassPath\"\n    }\n}\n\n# Check to see if liquibase path has been defined\nif ([string]::IsNullOrEmpty($liquibaseExecutablePath))\n{\n    # Assign root\n    $liquibaseExecutablePath = $PSSCriptRoot\n}\n\n# Get the executable location\n$liquibaseExecutable = Get-ChildItem -Path $liquibaseExecutablePath -Recurse | Where-Object {$_.Name -eq \"liquibase.bat\"}\n\n# Add path to current session\n$env:PATH += \";$($liquibaseExecutable.Directory)\"\n\n# Check to make sure it was found\nif ([string]::IsNullOrEmpty($liquibaseExecutable))\n{\n    # Could not find the executable\n    Write-Error \"Unable to find liquibase.bat in $PSScriptRoot or subfolders.\"\n}\n\n# Add argument for driver\n#$databaseDriver = Get-DatabaseDriverName -DatabaseType $liquibaseDatabaseType\n#if (![string]::IsNullOrEmpty($databaseDriver))\n#{\n#\t$liquibaseArguments += \"--driver=$databaseDriver\"\n#}\n\n# Add connection Url\n$connectionUrl = Get-ConnectionUrl -DatabaseType $liquibaseDatabaseType -ServerPort $liquibaseServerPort -ServerName $liquibaseServerName -DatabaseName $liquibaseDatabaseName -QueryStringParameters $liquibaseQueryStringParameters\n$liquibaseArguments += \"--url=$connectionUrl\"\n\n# Add Username and password\n$liquibaseArguments += \"--username=$liquibaseUsername\"\n$liquibaseArguments += \"--password=`\"$liquibasePassword`\"\"\n\n# Set the location to where the file is\nSet-Location -Path $changeLogFile.Directory\n\n# Check to see if it should run or just report\nif ($liquibaseReport -eq $true)\n{\n    # Set error action preference - updateSQL writes to stderr so this is to prevent errors from showing up\n    $ErrorActionPreference = \"SilentlyContinue\"\n    \n    # Add just report\n    $liquibaseArguments += \"updateSQL\"\n    \n    # Execute liquibase\n    $liquibaseProcess = Start-Process -FilePath $liquibaseExecutable.FullName -ArgumentList $liquibaseArguments -RedirectStandardError \"$PSScriptRoot\\stderr.txt\" -RedirectStandardOutput \"$PSScriptRoot\\ChangeSet.sql\" -Passthru -Wait\n\t    \n    # Display standard error\n    foreach ($line in (Get-Content -Path \"$PSScriptRoot\\stderr.txt\"))\n    {\n    \t# Display\n        Write-Host \"$line\"\n    }\n    \n    # Check exit code\n    if ($liquibaseProcess.ExitCode -eq 0)\n    {\n    \t# Attach artifact\n        New-OctopusArtifact -Path \"$PSScriptRoot\\ChangeSet.sql\" -Name \"ChangeSet.sql\"\n    }\n}\nelse\n{\n    $liquibaseArguments += \"update\"\n    & $liquibaseExecutable.FullName $liquibaseArguments\n}\n\n"
  },
  "Category": "Liquibase",
  "HistoryUrl": "https://github.com/OctopusDeploy/Library/commits/master/step-templates//opt/buildagent/work/75443764cd38076d/step-templates/liquibase-apply-changeset.json",
  "Website": "/step-templates/6a276a58-d082-425f-a77a-ff7b3979ce2e",
  "Logo": "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",
  "$Meta": {
    "Type": "ActionTemplate"
  }
}

History

Page updated on Thursday, February 25, 2021