From 731c0bf4851303e6e54d96c16d1ccc70ff44c6fe Mon Sep 17 00:00:00 2001 From: Twerthi Date: Tue, 20 Jan 2026 14:41:59 -0800 Subject: [PATCH 1/2] Adding check capabilities --- step-templates/flyway-state-based-migration.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/step-templates/flyway-state-based-migration.json b/step-templates/flyway-state-based-migration.json index 65847c880..f5ae9630d 100644 --- a/step-templates/flyway-state-based-migration.json +++ b/step-templates/flyway-state-based-migration.json @@ -3,7 +3,7 @@ "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.", "ActionType": "Octopus.Script", - "Version": 1, + "Version": 2, "CommunityActionTemplateId": null, "Packages": [ { @@ -23,7 +23,7 @@ "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.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# 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\nswitch($flywayCommand)\n{\n \"prepare\"\n {\n Execute-FlywayCommand -BinaryFilePath $flywayCmd -CommandArguments $prepareArguments\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 \"check\"\n {\n # Create array for check arguments\n $checkArguments = @(\"check\", \"-changes\", \"-check.changesSource=`\"schemaModel`\"\")\n $checkArguments += $arguments\n\n # Execute command\n Execute-FlywayCommand -BinaryFilePath $flywayCmd -CommandArguments $checkArguments\n\n # Attach generated report as Octopus Artifact\n if ((Test-Path -Path \"$flywayPackagePath/report.html\") -eq $true)\n {\n New-OctopusArtifact -Path \"$flywayPackagePath/report.html\" -Name \"$($flywayStepName)_$($flywayEnvironment)_$($currentDateFormatted).report.html\" \n }\n\n break\n }\n \"deploy\"\n {\n Execute-FlywayCommand -BinaryFilePath $flywayCmd -CommandArguments $prepareArguments # Prepare has to be run first to produce the scripts deploy needs\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" }, @@ -52,11 +52,11 @@ "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.", + "HelpText": "**Required**\n\nThe [flyway command](https://flywaydb.org/documentation/usage/commandline/) you wish to run.\n\n- `Check`: Produces a report of changes from the `schema model` against the target `environment`\n- `Deploy`: Executes the scripts generated to make the target database look like the model.\n- `Prepare`: Compares the schema model against the target database and generates scripts to make the database conform to the model.\n", "DefaultValue": "prepare", "DisplaySettings": { "Octopus.ControlType": "Select", - "Octopus.SelectOptions": "prepare|Prepare\ndeploy|Deploy" + "Octopus.SelectOptions": "check|Check\ndeploy|Deploy\ndeploy|Deploy\nprepare|Prepare" } }, { @@ -183,8 +183,8 @@ ], "StepPackageId": "Octopus.Script", "$Meta": { - "ExportedAt": "2025-10-31T15:45:05.259Z", - "OctopusVersion": "2025.3.14410", + "ExportedAt": "2026-01-20T22:39:29.598Z", + "OctopusVersion": "2025.4.10338", "Type": "ActionTemplate" }, "LastModifiedBy": "twerthi", From db1e593c6fea0f62f5172e4c032742e9ee0d3b74 Mon Sep 17 00:00:00 2001 From: Twerthi Date: Wed, 21 Jan 2026 10:05:05 -0800 Subject: [PATCH 2/2] Removing duplicate drop down option --- step-templates/flyway-state-based-migration.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/step-templates/flyway-state-based-migration.json b/step-templates/flyway-state-based-migration.json index f5ae9630d..c584ab08f 100644 --- a/step-templates/flyway-state-based-migration.json +++ b/step-templates/flyway-state-based-migration.json @@ -56,7 +56,7 @@ "DefaultValue": "prepare", "DisplaySettings": { "Octopus.ControlType": "Select", - "Octopus.SelectOptions": "check|Check\ndeploy|Deploy\ndeploy|Deploy\nprepare|Prepare" + "Octopus.SelectOptions": "check|Check\ndeploy|Deploy\nprepare|Prepare" } }, {