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.
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"
}
}
Page updated on Thursday, February 25, 2021