Octopus.Script exported 2025-10-31 by twerthi belongs to ‘Flyway’ category.
Step template to leverage Flyway to deploy migration scripts. This is the latest and greatest Flyway step template that leverages all the newest features of both Flyway and Octopus Deploy.
- You can include the flyway executables in your package, if you include the
flyway(Linux) orflyway.cmd(Windows) in the root of the package this step template will automatically find them. - You can use this with an execution container, negating the need to include Flyway in the package. If Flyway isn’t found in the package it will attempt to find
/flyway/flyway(when using Linux containers) orflywayin the environment path and use that. - Support for Flyway State Based commands, including the
undocommand. - Support for flyway community, teams, enterprise, and pro editions.
Please note this requires Octopus Deploy 2019.10.0 or newer along with PowerShell Core installed on the machines running this step. AWS EC2 IAM Authentication requires the AWS CLI to be installed.
Parameters
When steps based on the template are included in a project’s deployment process, the parameters below can be set.
Flyway Package
Flyway.Package.Value =
Required
The package containing the migration scripts you want Flyway to run. Please refer to documentation for core concepts and naming conventions.
Flyway Executable Path
Flyway.Executable.Path =
Optional
The path of the flyway executable. It can either be a relative path or an absolute path.
When not provided, this step template will test for the following. The step template places precedence on the version of the flyway included in the package. If Flyway is NOT found in the package, it will attempt to see if it is installed on the server by checking common paths.
Running on Linux:
.flyway: the package being deployed includes flyway and is running on Linux/flyway/flyway: The default path for the Linux execution container.
Running on Windows:
\.flyway.cmd: the package being deployed includes flyway and is running on Windowsflyway: the package is in the path on the Windows VM or Windows Execution container.
Flyway Command
Flyway.Command.Value = prepare
Required
The flyway command you wish to run.
Prepare: Compares the schema model against the target database and generates scripts to make the database conform to the model.Deploy: Executes the scripts generated to make the target database look like the model.
Email address
Flyway.Email.Address =
The email address associated with the Personal Access Token (PAT).
Personal Access Token (PAT)
Flyway.PersonalAccessToken =
The Personal Access Token (PAT) to authenticate with for Enterprise features.
Replaces the License Key.
-Url
Flyway.Target.Url =
Required
The URL parameter used in Flyway. This is the URL of the database to run the migration scripts on in the format specified in the default flyway.conf file.
Examples:
- SQL Server:
jdbc:sqlserver://host:port;databaseName=database - Oracle:
jdbc:oracle:thin:@//host:port/serviceorjdbc:oracle:thin:@tns_entry - MySQL:
jdbc:mysql://host:port/database - PostgreSQL:
jdbc:postgresql://host:port/database - SQLite:
jdbc:sqlite:database
Please refer to documentation for further examples.
Source Schema Model (optional).
Flyway.Source.Schema.Model =
Name of the source schema model used for the comparison operation. Not all database technologies, such as MSSQL, use this option.
Target Schema (optional)
Flyway.Target.Schema =
Name of the target schema to deploy to.
Authentication Method
Flyway.Authentication.Method = usernamepassword
Method used to authenticate to the database server.
-Schemas
Flyway.Command.Schemas =
Optional
Comma-separated case-sensitive list of schemas managed by Flyway.
Example: schema1,schema2
Flyway will attempt to create these schemas if they do not already exist and will clean them in the order of this list. If Flyway created them, then the schemas themselves will be dropped when cleaning.
The first schema in the list will act as the default schema.
Additional arguments
Flyway.Additional.Arguments =
Any additional arguments that need to be passed (ie `-table=“MyTable”)
Execute in transaction?
Flyway.Transaction = False
Tick this box if you want the deployment to execute within a transaction.
Generate Undo Script?
Flyway.Generate.Undo = False
Tick this box if you want Flwyay to generate an Undo script. Undo scripts will be created as an output variable for Prepare and attached as an Octopus Artifact for Deploy.
Script body
Steps based on this template will execute the following PowerShell script.
$VerboseActionPreference="Continue"
# Fix ANSI Color on PWSH Core issues when displaying objects
if ($PSEdition -eq "Core") {
$PSStyle.OutputRendering = "PlainText"
}
function Get-FlywayExecutablePath
{
param (
$providedPath
)
if ([string]::IsNullOrWhiteSpace($providedPath) -eq $false)
{
Write-Host "The executable path was provided, testing to see if it is absolute or relative"
if ([IO.Path]::IsPathRooted($providedPath))
{
Write-Host "The provided path is absolute, using that"
return $providedPath
}
Write-Host "The provided path was relative, combining $(Get-Location) with $providedPath"
return Join-Path $(Get-Location) $providedPath
}
Write-Host "Checking to see if we are currently running on Linux"
if ($IsLinux)
{
Write-Host "Currently running on Linux"
Write-Host "Checking to see if flyway was included with the package"
if (Test-Path "./flyway")
{
Write-Host "It was, using that version of flyway"
return "flyway"
}
Write-Host "Testing to see if we are on an execution container with /flyway/flyway as the path"
if (Test-Path "/flyway/flyway")
{
Write-Host "We are, using /flyway/flyway"
return "/flyway/flyway"
}
}
Write-Host "Currently running on Windows"
Write-Host "Testing to see if flyway.cmd was included with the package"
if (Test-Path ".\flyway.cmd")
{
Write-Host "It was, using that version."
return ".\flyway.cmd"
}
Write-Host "Testing to see if flyway can be found in the env path"
$flywayExecutable = (Get-Command "flyway" -ErrorAction SilentlyContinue)
if ($null -ne $flywayExecutable)
{
Write-Host "The flyway folder is part of the environment path"
return $flywayExecutable.Source
}
Fail-Step "Unable to find flyway executable. Please include it as part of the package, or provide the path to it."
}
function Get-ParsedUrl
{
# Define parameters
param (
$ConnectionUrl
)
# Remove the 'jdbc:' portion from the $ConnectionUrl parameter
$ConnectionUrl = $ConnectionUrl.ToLower().Replace("jdbc:", "")
# Parse and return the url
return [System.Uri]$ConnectionUrl
}
function Execute-FlywayCommand
{
# Define parameters
param(
$BinaryFilePath,
$CommandArguments
)
# Display what's going to be run
if (![string]::IsNullOrWhitespace($flywayUserPassword))
{
$flywayDisplayArguments = $CommandArguments.PSObject.Copy()
$arrayIndex = 0
for ($i = 0; $i -lt $flywayDisplayArguments.Count; $i++)
{
if ($null -ne $flywayDisplayArguments[$i])
{
if ($flywayDisplayArguments[$i].Contains($flywayUserPassword))
{
$flywayDisplayArguments[$i] = $flywayDisplayArguments[$i].Replace($flywayUserPassword, "****")
}
}
}
Write-Host "Executing the following command: $flywayCmd $flywayDisplayArguments"
}
else
{
Write-Host "Executing the following command: $flywayCmd $arguments"
}
# Adjust call to flyway command based on OS
if ($IsLinux)
{
& bash $BinaryFilePath $CommandArguments
}
else
{
& $BinaryFilePath $CommandArguments
}
}
# Declaring the path to the NuGet package
$flywayPackagePath = $OctopusParameters["Octopus.Action.Package[Flyway.Package.Value].ExtractedPath"]
$flywayUrl = $OctopusParameters["Flyway.Target.Url"]
$flywayUser = $OctopusParameters["Flyway.Database.User"]
$flywayUserPassword = $OctopusParameters["Flyway.Database.User.Password"]
$flywayCommand = $OctopusParameters["Flyway.Command.Value"]
$flywayLicenseEmail = $OctopusParameters["Flyway.Email.Address"]
$flywayLicensePAT = $OctopusParameters["Flyway.PersonalAccessToken"]
$flywayExecutablePath = $OctopusParameters["Flyway.Executable.Path"]
$flywaySchemas = $OctopusParameters["Flyway.Command.Schemas"]
$flywayAuthenticationMethod = $OctopusParameters["Flyway.Authentication.Method"]
$flywayAdditionalArguments = $OctopusParameters["Flyway.Additional.Arguments"]
$flywayStepName = $OctopusParameters["Octopus.Action.StepName"]
$flywayEnvironment = $OctopusParameters["Octopus.Environment.Name"]
$flywayTargetSchema = $OctopusParameters["Flyway.Target.Schema"]
$flywaySourceSchema = $OctopusParameters["Flyway.Source.Schema.Model"]
$flywayExecuteInTransaction = $OctopusParameters["Flyway.Transaction"]
$flywayUndoScript = [System.Convert]::ToBoolean($OctopusParameters["Flyway.Generate.Undo"])
# Logging for troubleshooting
Write-Host "*******************************************"
Write-Host "Logging variables:"
Write-Host " - - - - - - - - - - - - - - - - - - - - -"
Write-Host "PackagePath: $flywayPackagePath"
Write-Host "Flyway Executable Path: $flywayExecutablePath"
Write-Host "Flyway Command: $flywayCommand"
Write-Host "-url: $flywayUrl"
Write-Host "-user: $flywayUser"
Write-Host "-schemas: $flywaySchemas"
Write-Host "Source Schema Model: $flywaySourceSchema"
Write-Host "Target Schema: $flywayTargetSchema"
Write-Host "Execute in transaction: $flywayExecuteInTransaction"
Write-Host "Additional Arguments: $flywayAdditionalArguments"
Write-Host "Generate Undo script: $flywayUndoScript"
Write-Host "*******************************************"
if ($null -eq $IsWindows) {
Write-Host "Determining Operating System..."
$IsWindows = ([System.Environment]::OSVersion.Platform -eq "Win32NT")
$IsLinux = ([System.Environment]::OSVersion.Platform -eq "Unix")
}
Write-Host "Setting execution location to: $flywayPackagePath"
Set-Location $flywayPackagePath
$flywayCmd = Get-FlywayExecutablePath -providedPath $flywayExecutablePath
$commandToUse = $flywayCommand
$arguments = @()
# Deteremine authentication method
switch ($flywayAuthenticationMethod)
{
"awsiam"
{
# Check to see if OS is Windows and running in a container
if ($IsWindows -and $env:DOTNET_RUNNING_IN_CONTAINER)
{
throw "IAM Role authentication is not supported in a Windows container."
}
# Get parsed connection string url
$parsedUrl = Get-ParsedUrl -ConnectionUrl $flywayUrl
# Region is part of the RDS endpoint, extract
$region = ($parsedUrl.Host.Split("."))[2]
Write-Host "Generating AWS IAM token ..."
$flywayUserPassword = (aws rds generate-db-auth-token --hostname $parsedUrl.Host --region $region --port $parsedUrl.Port --username $flywayUser)
$arguments += "-user=`"$flywayUser`""
$arguments += "-password=`"$flywayUserPassword`""
break
}
"azuremanagedidentity"
{
# Check to see if OS is Windows and running in a container
if ($IsWindows -and $env:DOTNET_RUNNING_IN_CONTAINER)
{
throw "Azure Managed Identity is not supported in a Windows container."
}
# SQL Server driver doesn't assign password
if (!$flywayUrl.ToLower().Contains("jdbc:sqlserver:"))
{
# Get login token
Write-Host "Generating Azure Managed Identity token ..."
$token = Invoke-RestMethod -Method GET -Uri "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://ossrdbms-aad.database.windows.net" -Headers @{"MetaData" = "true"} -UseBasicParsing
$flywayUserPassword = $token.access_token
$arguments += "-password=`"$flywayUserPassword`""
$arguments += "-user=`"$flywayUser`""
}
else
{
# Check to see if the querstring parameter for Azure Managed Identity is present
if (!$flywayUrl.ToLower().Contains("authentication=activedirectorymsi"))
{
# Add the authentication piece to the jdbc url
if (!$flywayUrl.EndsWith(";"))
{
# Add the separator
$flywayUrl += ";"
}
# Add authentication piece
$flywayUrl += "Authentication=ActiveDirectoryMSI"
}
}
break
}
"gcpserviceaccount"
{
# Check to see if OS is Windows and running in a container
if ($IsWindows -and $env:DOTNET_RUNNING_IN_CONTAINER)
{
throw "GCP Service Account authentication is not supported in a Windows container."
}
# Define header
$header = @{ "Metadata-Flavor" = "Google"}
# Retrieve service accounts
$serviceAccounts = Invoke-RestMethod -Method Get -Uri "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/" -Headers $header -UseBasicParsing
# Results returned in plain text format, get into array and remove empty entries
$serviceAccounts = $serviceAccounts.Split([Environment]::NewLine, [StringSplitOptions]::RemoveEmptyEntries)
# Retreive the specific service account assigned to the VM
$serviceAccount = $serviceAccounts | Where-Object {$_.ToLower().Contains("iam.gserviceaccount.com") }
Write-Host "Generating GCP IAM token ..."
# Retrieve token for account
$token = Invoke-RestMethod -Method Get -Uri "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/$serviceAccount/token" -Headers $header -UseBasicParsing
$flywayUserPassword = $token.access_token
$arguments += "-user=`"$flywayUser`""
$arguments += "-password=`"$flywayUserPassword`""
#$env:FLYWAY_PASSWORD = $flywayUserPassword
break
}
"usernamepassword"
{
Write-Host "User provided, adding user and password command line argument"
$arguments += "-user=`"$flywayUser`""
$arguments += "-password=`"$flywayUserPassword`""
break
}
"windowsauthentication"
{
# Display to the user they've selected windows authentication. Though this is dictated by the jdbc url, this is added to make sure the user knows that's what is
# being used
Write-Host "Using Windows Authentication"
# Check for integratedauthentication=true in url
if (!$flywayUrl.ToLower().Contains("integratedsecurity=true"))
{
# Check to see if the connection url ends with a ;
if (!$flywayUrl.EndsWith(";"))
{
# Add the ;
$flywayUrl += ";"
}
$flywayUrl += "integratedSecurity=true;"
}
break
}
}
$arguments += "-url=`"$flywayUrl`""
if (![String]::IsNullOrWhitespace($flywaySchemas))
{
Write-Host "Schemas provided, adding schemas command line argument"
$arguments += "-schemas=`"$flywaySchemas`""
}
if (![string]::IsNullOrWhiteSpace($flywayLicenseEmail) -and ![string]::IsNullOrWhiteSpace($flywayLicensePAT))
{
Write-Host "Personal Access Token provided, adding -email and -token command line arguments"
$arguments += @("-email=`"$flywayLicenseEmail`"", "-token=`"$flywayLicensePAT`"")
}
Write-Host "Performing diff of schema model against $($flywayUrl)/$($flywayDatabase) ..."
# Locate schema-model folder
$packageFolders = Get-ChildItem -Path $flywayPackagePath -Recurse | ?{ $_.PSIsContainer } | Where-Object {$_.Name -eq "schema-model"}
if ($packageFolders -is [array])
{
Write-Error "Multiple 'schema-model' folders found!"
}
$modelFolderPath = $packageFolders.FullName
$arguments += "-environments.$flywayEnvironment.url=$flywayUrl"
$arguments += "-environment=$flywayEnvironment"
$arguments += "-schemaModelLocation=$modelFolderPath"
if (![string]::IsNullOrWhitespace($flywaySourceSchema))
{
$arguments += "-schemaModelSchemas=$flywaySourceSchema"
}
if (![string]::IsNullOrWhitespace($flywayTargetSchema))
{
$arguments += "-environments.$flywayEnvironment.schemas=$flywayTargetSchema"
}
# Execute diff
$diffArguments = @("diff")
$diffArguments += $arguments
$diffArguments += "-diff.source=schemaModel"
$diffArguments += "-diff.target=env:$flywayEnvironment"
$diffArguments += "-diff.artifactFilename=$flywayPackagePath/artifact.diff"
Execute-FlywayCommand -BinaryFilePath $flywayCmd -CommandArguments $diffArguments
# Check to see if there's any additional arguments to add
if (![string]::IsNullOrWhitespace($flywayAdditionalArguments))
{
# Split on space
$flywayAdditionalArgumentsArray = ($flywayAdditionalArguments.Split(" ", [System.StringSplitOptions]::RemoveEmptyEntries))
# Loop through array
foreach ($newArgument in $flywayAdditionalArgumentsArray)
{
# Add the arguments
$arguments += $newArgument
}
}
# Attempt to find driver path for java
$driverPath = (Get-ChildItem -Path (Get-ChildItem -Path $flywayCmd).Directory -Recurse | Where-Object {$_.PSIsContainer -eq $true -and $_.Name -eq "drivers"})
# If found, add driver path to the PATH environment varaible
if ($null -ne $driverPath)
{
$env:PATH += "$([IO.Path]::PathSeparator)$($driverPath.FullName)"
}
$currentDate = Get-Date
$currentDateFormatted = $currentDate.ToString("yyyyMMdd_HHmmss")
$prepareArguments = @("prepare")
$prepareArguments += $arguments
$prepareArguments += "-prepare.source=schemaModel"
$prepareArguments += "-prepare.target=env:$flywayEnvironment"
$prepareArguments += "-prepare.artifactFilename=$flywayPackagePath/artifact.diff"
$prepareArguments += "-prepare.scriptFilename=$flywayPackagePath/$($flywayStepName)_$($flywayEnvironment)_$($currentDateFormatted).sql"
if ($flywayUndoScript)
{
$prepareArguments += "-prepare.undoFilename=$flywayPackagePath/$($flywayStepName)_$($flywayEnvironment)_$($currentDateFormatted).undo.sql"
$prepareArguments += "-prepare.types=`"deploy,undo`""
}
Execute-FlywayCommand -BinaryFilePath $flywayCmd -CommandArguments $prepareArguments
switch($flywayCommand)
{
"prepare"
{
if ((Test-Path -Path "$flywayPackagePath/$($flywayStepName)_$($flywayEnvironment)_$($currentDateFormatted).sql") -eq $true)
{
$fileContents = Get-Content -Path "$flywayPackagePath/$($flywayStepName)_$($flywayEnvironment)_$($currentDateFormatted).sql"
Set-OctopusVariable -name "ScriptFile" -value "$fileContents"
Write-Host "Output variable with script contents: #{Octopus.Action[$flywayStepName].Output.Scriptfile}"
if ($flywayUndoScript)
{
$fileContents = Get-Content -Path "$flywayPackagePath/$($flywayStepName)_$($flywayEnvironment)_$($currentDateFormatted).undo.sql"
Set-OctopusVariable -name "UndoScriptFile" -value "$fileContents"
Write-Host "Output variable with script contents: #{Octopus.Action[$flywayStepName].Output.UndoScriptfile}"
}
}
break
}
"deploy"
{
if ((Test-Path -Path "$flywayPackagePath/$($flywayStepName)_$($flywayEnvironment)_$($currentDateFormatted).sql") -eq $true)
{
# Define deploy arguments
$deployArguments = @("deploy")
$deployArguments += $arguments
$deployArguments += "-deploy.scriptFilename=$flywayPackagePath/$($flywayStepName)_$($flywayEnvironment)_$($currentDateFormatted).sql"
$deployArguments += "-executeInTransaction=$flywayExecuteInTransaction"
Execute-FlywayCommand -BinaryFilePath $flywayCmd -CommandArguments $deployArguments
New-OctopusArtifact -Path "$flywayPackagePath/$($flywayStepName)_$($flywayEnvironment)_$($currentDateFormatted).sql" -Name "$($flywayStepName)_$($flywayEnvironment)_$($currentDateFormatted).sql"
if ($flywayUndoScript)
{
New-OctopusArtifact -Path "$flywayPackagePath/$($flywayStepName)_$($flywayEnvironment)_$($currentDateFormatted).undo.sql" -Name "$($flywayStepName)_$($flywayEnvironment)_$($currentDateFormatted).undo.sql"
}
}
else
{
Write-Host "Script file not found!"
}
}
}
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": "67a28755-049e-4cec-b45c-3e5047350d8d",
"Name": "Flyway State Based Migration",
"Description": "Step template to leverage Flyway to deploy migration scripts. This is the latest and greatest Flyway step template that leverages all the newest features of both Flyway and Octopus Deploy.\n\n- You can include the flyway executables in your package, if you include the `flyway` (Linux) or `flyway.cmd` (Windows) in the root of the package this step template will automatically find them.\n- You can use this with an execution container, negating the need to include Flyway in the package. If Flyway isn't found in the package it will attempt to find `/flyway/flyway` (when using Linux containers) or `flyway` in the environment path and use that.\n- Support for Flyway State Based commands, including the `undo` command.\n- Support for flyway community, teams, enterprise, and pro editions. \n\nPlease note this requires Octopus Deploy **2019.10.0** or newer along with PowerShell Core installed on the machines running this step.\nAWS EC2 IAM Authentication requires the AWS CLI to be installed.",
"Version": 1,
"ExportedAt": "2025-10-31T15:45:05.259Z",
"ActionType": "Octopus.Script",
"Author": "twerthi",
"Packages": [
{
"Id": "0c0d333c-d794-4a16-a3a2-4bbba4550763",
"Name": "Flyway.Package.Value",
"PackageId": null,
"FeedId": null,
"AcquisitionLocation": "Server",
"Properties": {
"Extract": "True",
"SelectionMode": "deferred",
"PackageParameterName": "Flyway.Package.Value"
}
}
],
"Parameters": [
{
"Id": "5952088c-d399-4050-9474-d93aef737a8d",
"Name": "Flyway.Package.Value",
"Label": "Flyway Package",
"HelpText": "**Required**\n\nThe package containing the migration scripts you want Flyway to run. Please refer to [documentation](https://flywaydb.org/documentation/concepts/migrations) for core concepts and naming conventions.",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "Package"
}
},
{
"Id": "1a2c32aa-5bf5-41ef-a916-4fa5c4039748",
"Name": "Flyway.Executable.Path",
"Label": "Flyway Executable Path",
"HelpText": "**Optional**\n\nThe path of the flyway executable. It can either be a relative path or an absolute path.\n\nWhen not provided, this step template will test for the following. The step template places precedence on the version of the flyway included in the package. If Flyway is NOT found in the package, it will attempt to see if it is installed on the server by checking common paths.\n\nRunning on `Linux`:\n- `.flyway`: the package being deployed includes flyway and is running on Linux\n- `/flyway/flyway`: The default path for the Linux execution container.\n\nRunning on Windows:\n- `\\.flyway.cmd`: the package being deployed includes flyway and is running on Windows\n- `flyway`: the package is in the path on the Windows VM or Windows Execution container.",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "SingleLineText"
}
},
{
"Id": "ce396114-d0e6-433f-a160-6ea92b26b1b2",
"Name": "Flyway.Command.Value",
"Label": "Flyway Command",
"HelpText": "**Required**\n\nThe [flyway command](https://flywaydb.org/documentation/usage/commandline/) you wish to run.\n\n- `Prepare`: Compares the schema model against the target database and generates scripts to make the database conform to the model.\n- `Deploy`: Executes the scripts generated to make the target database look like the model.",
"DefaultValue": "prepare",
"DisplaySettings": {
"Octopus.ControlType": "Select",
"Octopus.SelectOptions": "prepare|Prepare\ndeploy|Deploy"
}
},
{
"Id": "b05cb50e-1e34-4c2d-bf3f-b7bbdc555f05",
"Name": "Flyway.Email.Address",
"Label": "Email address",
"HelpText": "The email address associated with the Personal Access Token (PAT).",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "SingleLineText"
}
},
{
"Id": "24c6fe79-6fbd-4f19-9f74-a36cda746ced",
"Name": "Flyway.PersonalAccessToken",
"Label": "Personal Access Token (PAT)",
"HelpText": "The Personal Access Token (PAT) to authenticate with for Enterprise features. \n\nReplaces the License Key.",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "Sensitive"
}
},
{
"Id": "522f4dc8-3a0a-486d-a9cd-9c2ef94d1a8e",
"Name": "Flyway.Target.Url",
"Label": "-Url",
"HelpText": "**Required**\n\nThe [URL](https://flywaydb.org/documentation/configuration/parameters/url) parameter used in Flyway. This is the URL of the database to run the migration scripts on in the format specified in the default flyway.conf file.\n\nExamples:\n- SQL Server: `jdbc:sqlserver://host:port;databaseName=database`\n- Oracle: `jdbc:oracle:thin:@//host:port/service` or `jdbc:oracle:thin:@tns_entry`\n- MySQL: `jdbc:mysql://host:port/database`\n- PostgreSQL: `jdbc:postgresql://host:port/database`\n- SQLite: `jdbc:sqlite:database`\n\nPlease refer to [documentation](https://flywaydb.org/documentation/database/sqlserver) for further examples.",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "SingleLineText"
}
},
{
"Id": "349f8a5f-5a18-4d23-a717-1c74a03029eb",
"Name": "Flyway.Source.Schema.Model",
"Label": "Source Schema Model (optional).",
"HelpText": "Name of the source schema model used for the comparison operation. Not all database technologies, such as MSSQL, use this option.",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "SingleLineText"
}
},
{
"Id": "195e2486-f286-4a72-a97a-f40b7a44a609",
"Name": "Flyway.Target.Schema",
"Label": "Target Schema (optional)",
"HelpText": "Name of the target schema to deploy to.",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "SingleLineText"
}
},
{
"Id": "16d4243a-28b0-4e8d-beec-854ca4c781b0",
"Name": "Flyway.Authentication.Method",
"Label": "Authentication Method",
"HelpText": "Method used to authenticate to the database server.",
"DefaultValue": "usernamepassword",
"DisplaySettings": {
"Octopus.ControlType": "Select",
"Octopus.SelectOptions": "awsiam|AWS EC2 IAM Role\nazuremanagedidentity|Azure Managed Identity\ngcpserviceaccount|GCP Service Account\nusernamepassword|Username\\Password\nwindowsauthentication|Windows Authentication"
}
},
{
"Id": "3f733c39-c99a-40d0-9dfd-e67d72c87883",
"Name": "Flyway.Database.User",
"Label": "-User",
"HelpText": "**Optional**\n\nThe [user](https://flywaydb.org/documentation/configuration/parameters/user) used to connect to the database.",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "SingleLineText"
}
},
{
"Id": "7509e8ee-c781-4ca2-bbe4-6e5e348d3d44",
"Name": "Flyway.Database.User.Password",
"Label": "-Password",
"HelpText": "**Optional**\n\nThe [password](https://flywaydb.org/documentation/configuration/parameters/password) used to connect to the database.",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "Sensitive"
}
},
{
"Id": "6d4946a4-0746-40e9-9b6e-c85c220c2dbe",
"Name": "Flyway.Command.Schemas",
"Label": "-Schemas",
"HelpText": "**Optional**\n\nComma-separated case-sensitive list of [schemas](https://flywaydb.org/documentation/configuration/parameters/schemas) managed by Flyway. \n\nExample: `schema1,schema2`\n\nFlyway will attempt to create these schemas if they do not already exist and will clean them in the order of this list. If Flyway created them, then the schemas themselves will be dropped when cleaning.\n\nThe first schema in the list will act as the default schema.",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "SingleLineText"
}
},
{
"Id": "12168dc6-261b-4853-89ea-ef4e36e17452",
"Name": "Flyway.Additional.Arguments",
"Label": "Additional arguments",
"HelpText": "Any additional arguments that need to be passed (ie `-table=\"MyTable\")",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "SingleLineText"
}
},
{
"Id": "7c7a8183-963d-40e5-94e9-b7a6aa2217df",
"Name": "Flyway.Transaction",
"Label": "Execute in transaction?",
"HelpText": "Tick this box if you want the deployment to execute within a transaction.",
"DefaultValue": "False",
"DisplaySettings": {
"Octopus.ControlType": "Checkbox"
}
},
{
"Id": "291b9675-e737-4dfe-98fc-bbf303a87653",
"Name": "Flyway.Generate.Undo",
"Label": "Generate Undo Script?",
"HelpText": "Tick this box if you want Flwyay to generate an `Undo` script. `Undo` scripts will be created as an output variable for `Prepare` and attached as an Octopus Artifact for `Deploy`.",
"DefaultValue": "False",
"DisplaySettings": {
"Octopus.ControlType": "Checkbox"
}
}
],
"Properties": {
"Octopus.Action.Script.ScriptSource": "Inline",
"Octopus.Action.Script.Syntax": "PowerShell",
"Octopus.Action.Script.ScriptBody": "$VerboseActionPreference=\"Continue\"\n\n# Fix ANSI Color on PWSH Core issues when displaying objects\nif ($PSEdition -eq \"Core\") {\n $PSStyle.OutputRendering = \"PlainText\"\n}\n\nfunction Get-FlywayExecutablePath\n{\n\tparam (\n \t$providedPath\n )\n \n if ([string]::IsNullOrWhiteSpace($providedPath) -eq $false)\n {\n \tWrite-Host \"The executable path was provided, testing to see if it is absolute or relative\"\n\t\tif ([IO.Path]::IsPathRooted($providedPath))\n {\n \tWrite-Host \"The provided path is absolute, using that\"\n \n \treturn $providedPath\n }\n \n Write-Host \"The provided path was relative, combining $(Get-Location) with $providedPath\"\n return Join-Path $(Get-Location) $providedPath\n }\n \n Write-Host \"Checking to see if we are currently running on Linux\"\n if ($IsLinux) \n {\n \tWrite-Host \"Currently running on Linux\"\n \tWrite-Host \"Checking to see if flyway was included with the package\"\n \tif (Test-Path \"./flyway\")\n {\n \tWrite-Host \"It was, using that version of flyway\"\n \treturn \"flyway\"\n }\n \n Write-Host \"Testing to see if we are on an execution container with /flyway/flyway as the path\"\n \tif (Test-Path \"/flyway/flyway\")\n {\n \tWrite-Host \"We are, using /flyway/flyway\"\n \treturn \"/flyway/flyway\"\n } \n }\n \n Write-Host \"Currently running on Windows\"\n \n Write-Host \"Testing to see if flyway.cmd was included with the package\"\n if (Test-Path \".\\flyway.cmd\")\n {\n \tWrite-Host \"It was, using that version.\"\n \treturn \".\\flyway.cmd\"\n }\n \n Write-Host \"Testing to see if flyway can be found in the env path\"\n $flywayExecutable = (Get-Command \"flyway\" -ErrorAction SilentlyContinue)\n if ($null -ne $flywayExecutable)\n {\n \tWrite-Host \"The flyway folder is part of the environment path\"\n return $flywayExecutable.Source\n }\n \n Fail-Step \"Unable to find flyway executable. Please include it as part of the package, or provide the path to it.\"\n}\n\nfunction Get-ParsedUrl\n{\n\t# Define parameters\n param (\n \t$ConnectionUrl\n )\n \n # Remove the 'jdbc:' portion from the $ConnectionUrl parameter\n $ConnectionUrl = $ConnectionUrl.ToLower().Replace(\"jdbc:\", \"\")\n \n # Parse and return the url\n return [System.Uri]$ConnectionUrl\n}\n\nfunction Execute-FlywayCommand\n{\n # Define parameters\n param(\n $BinaryFilePath,\n $CommandArguments\n )\n\n # Display what's going to be run\n if (![string]::IsNullOrWhitespace($flywayUserPassword))\n {\n $flywayDisplayArguments = $CommandArguments.PSObject.Copy()\n $arrayIndex = 0\n for ($i = 0; $i -lt $flywayDisplayArguments.Count; $i++)\n {\n if ($null -ne $flywayDisplayArguments[$i])\n {\n if ($flywayDisplayArguments[$i].Contains($flywayUserPassword))\n {\n $flywayDisplayArguments[$i] = $flywayDisplayArguments[$i].Replace($flywayUserPassword, \"****\")\n }\n }\n }\n\n Write-Host \"Executing the following command: $flywayCmd $flywayDisplayArguments\"\n }\n else\n {\n Write-Host \"Executing the following command: $flywayCmd $arguments\"\n } \n\n # Adjust call to flyway command based on OS\n if ($IsLinux)\n {\n & bash $BinaryFilePath $CommandArguments\n }\n else\n {\n & $BinaryFilePath $CommandArguments\n } \n}\n\n# Declaring the path to the NuGet package\n$flywayPackagePath = $OctopusParameters[\"Octopus.Action.Package[Flyway.Package.Value].ExtractedPath\"]\n$flywayUrl = $OctopusParameters[\"Flyway.Target.Url\"]\n$flywayUser = $OctopusParameters[\"Flyway.Database.User\"]\n$flywayUserPassword = $OctopusParameters[\"Flyway.Database.User.Password\"]\n$flywayCommand = $OctopusParameters[\"Flyway.Command.Value\"]\n$flywayLicenseEmail = $OctopusParameters[\"Flyway.Email.Address\"]\n$flywayLicensePAT = $OctopusParameters[\"Flyway.PersonalAccessToken\"]\n$flywayExecutablePath = $OctopusParameters[\"Flyway.Executable.Path\"]\n$flywaySchemas = $OctopusParameters[\"Flyway.Command.Schemas\"]\n$flywayAuthenticationMethod = $OctopusParameters[\"Flyway.Authentication.Method\"]\n$flywayAdditionalArguments = $OctopusParameters[\"Flyway.Additional.Arguments\"]\n$flywayStepName = $OctopusParameters[\"Octopus.Action.StepName\"]\n$flywayEnvironment = $OctopusParameters[\"Octopus.Environment.Name\"]\n$flywayTargetSchema = $OctopusParameters[\"Flyway.Target.Schema\"]\n$flywaySourceSchema = $OctopusParameters[\"Flyway.Source.Schema.Model\"]\n$flywayExecuteInTransaction = $OctopusParameters[\"Flyway.Transaction\"]\n$flywayUndoScript = [System.Convert]::ToBoolean($OctopusParameters[\"Flyway.Generate.Undo\"])\n\n\n# Logging for troubleshooting\nWrite-Host \"*******************************************\"\nWrite-Host \"Logging variables:\"\nWrite-Host \" - - - - - - - - - - - - - - - - - - - - -\"\nWrite-Host \"PackagePath: $flywayPackagePath\"\nWrite-Host \"Flyway Executable Path: $flywayExecutablePath\"\nWrite-Host \"Flyway Command: $flywayCommand\"\nWrite-Host \"-url: $flywayUrl\"\nWrite-Host \"-user: $flywayUser\"\nWrite-Host \"-schemas: $flywaySchemas\"\nWrite-Host \"Source Schema Model: $flywaySourceSchema\"\nWrite-Host \"Target Schema: $flywayTargetSchema\"\nWrite-Host \"Execute in transaction: $flywayExecuteInTransaction\"\nWrite-Host \"Additional Arguments: $flywayAdditionalArguments\"\nWrite-Host \"Generate Undo script: $flywayUndoScript\"\nWrite-Host \"*******************************************\"\n\nif ($null -eq $IsWindows) {\n Write-Host \"Determining Operating System...\"\n $IsWindows = ([System.Environment]::OSVersion.Platform -eq \"Win32NT\")\n $IsLinux = ([System.Environment]::OSVersion.Platform -eq \"Unix\")\n}\n\nWrite-Host \"Setting execution location to: $flywayPackagePath\"\nSet-Location $flywayPackagePath\n\n$flywayCmd = Get-FlywayExecutablePath -providedPath $flywayExecutablePath\n\n$commandToUse = $flywayCommand\n\n$arguments = @()\n\n# Deteremine authentication method\nswitch ($flywayAuthenticationMethod)\n{\n\t\"awsiam\"\n {\n\t\t# Check to see if OS is Windows and running in a container\n if ($IsWindows -and $env:DOTNET_RUNNING_IN_CONTAINER)\n {\n \tthrow \"IAM Role authentication is not supported in a Windows container.\"\n }\n\n\t\t# Get parsed connection string url\n $parsedUrl = Get-ParsedUrl -ConnectionUrl $flywayUrl\n \n # Region is part of the RDS endpoint, extract\n $region = ($parsedUrl.Host.Split(\".\"))[2]\n\n\t\tWrite-Host \"Generating AWS IAM token ...\"\n\t\t$flywayUserPassword = (aws rds generate-db-auth-token --hostname $parsedUrl.Host --region $region --port $parsedUrl.Port --username $flywayUser)\n\n\t\t$arguments += \"-user=`\"$flywayUser`\"\"\n \t$arguments += \"-password=`\"$flywayUserPassword`\"\"\n\n\t\tbreak\n }\n\t\"azuremanagedidentity\"\n {\n\t\t# Check to see if OS is Windows and running in a container\n if ($IsWindows -and $env:DOTNET_RUNNING_IN_CONTAINER)\n {\n \tthrow \"Azure Managed Identity is not supported in a Windows container.\"\n }\n \n # SQL Server driver doesn't assign password\n if (!$flywayUrl.ToLower().Contains(\"jdbc:sqlserver:\"))\n { \n # Get login token\n Write-Host \"Generating Azure Managed Identity token ...\"\n $token = Invoke-RestMethod -Method GET -Uri \"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://ossrdbms-aad.database.windows.net\" -Headers @{\"MetaData\" = \"true\"} -UseBasicParsing\n\n $flywayUserPassword = $token.access_token\n $arguments += \"-password=`\"$flywayUserPassword`\"\"\n $arguments += \"-user=`\"$flywayUser`\"\"\n }\n else\n {\n \n\t\t\t# Check to see if the querstring parameter for Azure Managed Identity is present\n if (!$flywayUrl.ToLower().Contains(\"authentication=activedirectorymsi\"))\n {\n # Add the authentication piece to the jdbc url\n if (!$flywayUrl.EndsWith(\";\"))\n {\n \t# Add the separator\n $flywayUrl += \";\"\n }\n \n # Add authentication piece\n $flywayUrl += \"Authentication=ActiveDirectoryMSI\"\n }\n }\n \n break\n }\n \"gcpserviceaccount\"\n {\n\t\t# Check to see if OS is Windows and running in a container\n if ($IsWindows -and $env:DOTNET_RUNNING_IN_CONTAINER)\n {\n \tthrow \"GCP Service Account authentication is not supported in a Windows container.\"\n }\n \n # Define header\n $header = @{ \"Metadata-Flavor\" = \"Google\"}\n\n # Retrieve service accounts\n $serviceAccounts = Invoke-RestMethod -Method Get -Uri \"http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/\" -Headers $header -UseBasicParsing\n\n # Results returned in plain text format, get into array and remove empty entries\n $serviceAccounts = $serviceAccounts.Split([Environment]::NewLine, [StringSplitOptions]::RemoveEmptyEntries)\n\n # Retreive the specific service account assigned to the VM\n $serviceAccount = $serviceAccounts | Where-Object {$_.ToLower().Contains(\"iam.gserviceaccount.com\") }\n\n\t\tWrite-Host \"Generating GCP IAM token ...\"\n # Retrieve token for account\n $token = Invoke-RestMethod -Method Get -Uri \"http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/$serviceAccount/token\" -Headers $header -UseBasicParsing\n \n $flywayUserPassword = $token.access_token\n \n $arguments += \"-user=`\"$flywayUser`\"\"\n $arguments += \"-password=`\"$flywayUserPassword`\"\"\n #$env:FLYWAY_PASSWORD = $flywayUserPassword\n \n break\n } \n \"usernamepassword\"\n {\n Write-Host \"User provided, adding user and password command line argument\"\n $arguments += \"-user=`\"$flywayUser`\"\"\n $arguments += \"-password=`\"$flywayUserPassword`\"\"\n \n break\n }\n \"windowsauthentication\"\n {\n \t# Display to the user they've selected windows authentication. Though this is dictated by the jdbc url, this is added to make sure the user knows that's what is\n # being used\n Write-Host \"Using Windows Authentication\"\n \n # Check for integratedauthentication=true in url\n if (!$flywayUrl.ToLower().Contains(\"integratedsecurity=true\"))\n {\n \t# Check to see if the connection url ends with a ;\n if (!$flywayUrl.EndsWith(\";\"))\n {\n \t# Add the ;\n $flywayUrl += \";\"\n }\n \n $flywayUrl += \"integratedSecurity=true;\"\n }\n break\n }\n}\n\n$arguments += \"-url=`\"$flywayUrl`\"\"\n\nif (![String]::IsNullOrWhitespace($flywaySchemas))\n{\n\tWrite-Host \"Schemas provided, adding schemas command line argument\"\n\t$arguments += \"-schemas=`\"$flywaySchemas`\"\" \n}\n\nif (![string]::IsNullOrWhiteSpace($flywayLicenseEmail) -and ![string]::IsNullOrWhiteSpace($flywayLicensePAT))\n{\n Write-Host \"Personal Access Token provided, adding -email and -token command line arguments\"\n $arguments += @(\"-email=`\"$flywayLicenseEmail`\"\", \"-token=`\"$flywayLicensePAT`\"\")\n}\n\nWrite-Host \"Performing diff of schema model against $($flywayUrl)/$($flywayDatabase) ...\"\n\n# Locate schema-model folder\n$packageFolders = Get-ChildItem -Path $flywayPackagePath -Recurse | ?{ $_.PSIsContainer } | Where-Object {$_.Name -eq \"schema-model\"}\n\nif ($packageFolders -is [array])\n{\n Write-Error \"Multiple 'schema-model' folders found!\"\n}\n\n$modelFolderPath = $packageFolders.FullName\n\n$arguments += \"-environments.$flywayEnvironment.url=$flywayUrl\"\n$arguments += \"-environment=$flywayEnvironment\"\n$arguments += \"-schemaModelLocation=$modelFolderPath\"\nif (![string]::IsNullOrWhitespace($flywaySourceSchema))\n{\n $arguments += \"-schemaModelSchemas=$flywaySourceSchema\"\n}\nif (![string]::IsNullOrWhitespace($flywayTargetSchema))\n{\n $arguments += \"-environments.$flywayEnvironment.schemas=$flywayTargetSchema\"\n}\n\n# Execute diff\n$diffArguments = @(\"diff\")\n$diffArguments += $arguments\n$diffArguments += \"-diff.source=schemaModel\"\n$diffArguments += \"-diff.target=env:$flywayEnvironment\"\n$diffArguments += \"-diff.artifactFilename=$flywayPackagePath/artifact.diff\"\n\nExecute-FlywayCommand -BinaryFilePath $flywayCmd -CommandArguments $diffArguments\n\n# Check to see if there's any additional arguments to add\nif (![string]::IsNullOrWhitespace($flywayAdditionalArguments))\n{\n\t# Split on space\n $flywayAdditionalArgumentsArray = ($flywayAdditionalArguments.Split(\" \", [System.StringSplitOptions]::RemoveEmptyEntries))\n\n # Loop through array\n foreach ($newArgument in $flywayAdditionalArgumentsArray)\n {\n \t# Add the arguments\n \t$arguments += $newArgument\n }\n}\n\n\n\n# Attempt to find driver path for java\n$driverPath = (Get-ChildItem -Path (Get-ChildItem -Path $flywayCmd).Directory -Recurse | Where-Object {$_.PSIsContainer -eq $true -and $_.Name -eq \"drivers\"})\n\n# If found, add driver path to the PATH environment varaible\nif ($null -ne $driverPath)\n{\n\t$env:PATH += \"$([IO.Path]::PathSeparator)$($driverPath.FullName)\"\n}\n\n$currentDate = Get-Date\n$currentDateFormatted = $currentDate.ToString(\"yyyyMMdd_HHmmss\")\n\n$prepareArguments = @(\"prepare\")\n$prepareArguments += $arguments\n$prepareArguments += \"-prepare.source=schemaModel\"\n$prepareArguments += \"-prepare.target=env:$flywayEnvironment\"\n$prepareArguments += \"-prepare.artifactFilename=$flywayPackagePath/artifact.diff\"\n$prepareArguments += \"-prepare.scriptFilename=$flywayPackagePath/$($flywayStepName)_$($flywayEnvironment)_$($currentDateFormatted).sql\"\n\nif ($flywayUndoScript)\n{\n $prepareArguments += \"-prepare.undoFilename=$flywayPackagePath/$($flywayStepName)_$($flywayEnvironment)_$($currentDateFormatted).undo.sql\"\n $prepareArguments += \"-prepare.types=`\"deploy,undo`\"\"\n}\n\nExecute-FlywayCommand -BinaryFilePath $flywayCmd -CommandArguments $prepareArguments\n\nswitch($flywayCommand)\n{\n \"prepare\"\n {\n if ((Test-Path -Path \"$flywayPackagePath/$($flywayStepName)_$($flywayEnvironment)_$($currentDateFormatted).sql\") -eq $true)\n {\n $fileContents = Get-Content -Path \"$flywayPackagePath/$($flywayStepName)_$($flywayEnvironment)_$($currentDateFormatted).sql\"\n Set-OctopusVariable -name \"ScriptFile\" -value \"$fileContents\"\n Write-Host \"Output variable with script contents: #{Octopus.Action[$flywayStepName].Output.Scriptfile}\"\n\n if ($flywayUndoScript)\n {\n $fileContents = Get-Content -Path \"$flywayPackagePath/$($flywayStepName)_$($flywayEnvironment)_$($currentDateFormatted).undo.sql\"\n Set-OctopusVariable -name \"UndoScriptFile\" -value \"$fileContents\"\n Write-Host \"Output variable with script contents: #{Octopus.Action[$flywayStepName].Output.UndoScriptfile}\"\n }\n }\n\n break\n }\n \"deploy\"\n {\n if ((Test-Path -Path \"$flywayPackagePath/$($flywayStepName)_$($flywayEnvironment)_$($currentDateFormatted).sql\") -eq $true)\n {\n # Define deploy arguments\n $deployArguments = @(\"deploy\")\n $deployArguments += $arguments\n $deployArguments += \"-deploy.scriptFilename=$flywayPackagePath/$($flywayStepName)_$($flywayEnvironment)_$($currentDateFormatted).sql\"\n $deployArguments += \"-executeInTransaction=$flywayExecuteInTransaction\"\n\n Execute-FlywayCommand -BinaryFilePath $flywayCmd -CommandArguments $deployArguments\n\n New-OctopusArtifact -Path \"$flywayPackagePath/$($flywayStepName)_$($flywayEnvironment)_$($currentDateFormatted).sql\" -Name \"$($flywayStepName)_$($flywayEnvironment)_$($currentDateFormatted).sql\"\n\n if ($flywayUndoScript)\n {\n New-OctopusArtifact -Path \"$flywayPackagePath/$($flywayStepName)_$($flywayEnvironment)_$($currentDateFormatted).undo.sql\" -Name \"$($flywayStepName)_$($flywayEnvironment)_$($currentDateFormatted).undo.sql\"\n }\n }\n else\n {\n Write-Host \"Script file not found!\"\n }\n }\n}",
"Octopus.Action.PowerShell.Edition": "Core",
"Octopus.Action.EnabledFeatures": "Octopus.Features.SelectPowerShellEditionForWindows"
},
"Category": "Flyway",
"HistoryUrl": "https://github.com/OctopusDeploy/Library/commits/master/step-templates//opt/buildagent/work/a381802920158308/step-templates/flyway-state-based-migration.json",
"Website": "/step-templates/67a28755-049e-4cec-b45c-3e5047350d8d",
"Logo": "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",
"$Meta": {
"Type": "ActionTemplate"
}
}
Page updated on Friday, October 31, 2025