Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 46 additions & 9 deletions Tasks/SqlAzureDacpacDeploymentV1/SqlAzureActions.ps1
Original file line number Diff line number Diff line change
@@ -1,3 +1,31 @@
$featureFlags = @{
enableUserOutputPath = Get-VstsPipelineFeature -FeatureName 'SqlAzureDacpac.EnableUserOutputPath'
}

function Get-EffectiveOutputPath {
param (
[string] $defaultOutputPath,
[string] $additionalArguments
)

$result = @{
EffectiveOutputPath = $defaultOutputPath
ResolvedFilePath = $defaultOutputPath
}

if ($featureFlags.enableUserOutputPath -and $additionalArguments -and $additionalArguments -imatch '/OutputPath\s*:\s*(?:"[^"]+"|[^\s]+)') {
Comment thread
v-dko marked this conversation as resolved.
$userPath = ($Matches[0] -replace '(?i)^/OutputPath\s*:\s*').Trim('"')
if ([string]::IsNullOrWhiteSpace($userPath)) {
throw "User-provided /OutputPath is empty or invalid."
}
Write-Verbose "User-provided /OutputPath detected: $userPath. Skipping default output path."
$result.EffectiveOutputPath = $null
Comment thread
v-dko marked this conversation as resolved.
$result.ResolvedFilePath = $userPath
}

return $result
}

function Extract-Dacpac {
param (
[string] $serverName,
Expand Down Expand Up @@ -94,11 +122,14 @@ function Deploy-Report {
$publishProfilePath = Find-SqlFiles -filePathPattern $publishProfile -verboseMessage (Get-VstsLocString -Key "SAD_PublishProfilePath") -throwIfMultipleFilesOrNoFilePresent
}

$outputXmlPath = "$ENV:SYSTEM_DEFAULTWORKINGDIRECTORY\GeneratedOutputFiles\${databaseName}_DeployReport.xml"
$defaultOutputXmlPath = "$ENV:SYSTEM_DEFAULTWORKINGDIRECTORY\GeneratedOutputFiles\${databaseName}_DeployReport.xml"
$outputPathResult = Get-EffectiveOutputPath -defaultOutputPath $defaultOutputXmlPath -additionalArguments $sqlpackageAdditionalArguments
$effectiveOutputPath = $outputPathResult.EffectiveOutputPath
$outputXmlPath = $outputPathResult.ResolvedFilePath
Comment thread
v-dko marked this conversation as resolved.

$sqlpackageArguments = Get-SqlPackageCommandArguments -authenticationType $authenticationType -sqlpackageAction "DeployReport" -sourceFile $dacpacFilePath -publishProfile $publishProfilePath -targetServerName $serverName -targetDatabaseName $databaseName -targetUser $sqlUsername -targetPassword $sqlPassword -targetConnectionString $connectionString -outputPath $outputXmlPath -additionalArguments $sqlpackageAdditionalArguments -token $token
$sqlpackageArguments = Get-SqlPackageCommandArguments -authenticationType $authenticationType -sqlpackageAction "DeployReport" -sourceFile $dacpacFilePath -publishProfile $publishProfilePath -targetServerName $serverName -targetDatabaseName $databaseName -targetUser $sqlUsername -targetPassword $sqlPassword -targetConnectionString $connectionString -outputPath $effectiveOutputPath -additionalArguments $sqlpackageAdditionalArguments -token $token

$sqlpackageArgumentsToBeLogged = Get-SqlPackageCommandArguments -authenticationType $authenticationType -sqlpackageAction "DeployReport" -sourceFile $dacpacFilePath -publishProfile $publishProfilePath -targetServerName $serverName -targetDatabaseName $databaseName -targetUser $sqlUsername -targetPassword $sqlPassword -targetConnectionString $connectionString -outputPath $outputXmlPath -additionalArguments $sqlpackageAdditionalArguments -isOutputSecure -token $token
$sqlpackageArgumentsToBeLogged = Get-SqlPackageCommandArguments -authenticationType $authenticationType -sqlpackageAction "DeployReport" -sourceFile $dacpacFilePath -publishProfile $publishProfilePath -targetServerName $serverName -targetDatabaseName $databaseName -targetUser $sqlUsername -targetPassword $sqlPassword -targetConnectionString $connectionString -outputPath $effectiveOutputPath -additionalArguments $sqlpackageAdditionalArguments -isOutputSecure -token $token

Execute-SqlPackage -sqlpackageArguments $sqlpackageArguments -sqlpackageArgumentsToBeLogged $sqlpackageArgumentsToBeLogged

Expand All @@ -120,11 +151,14 @@ function Drift-Report {
[string] $token
)

$outputXmlPath = "$ENV:SYSTEM_DEFAULTWORKINGDIRECTORY\GeneratedOutputFiles\${databaseName}_DriftReport.xml"
$defaultOutputXmlPath = "$ENV:SYSTEM_DEFAULTWORKINGDIRECTORY\GeneratedOutputFiles\${databaseName}_DriftReport.xml"
$outputPathResult = Get-EffectiveOutputPath -defaultOutputPath $defaultOutputXmlPath -additionalArguments $sqlpackageAdditionalArguments
$effectiveOutputPath = $outputPathResult.EffectiveOutputPath
$outputXmlPath = $outputPathResult.ResolvedFilePath

$sqlpackageArguments = Get-SqlPackageCommandArguments -authenticationType $authenticationType -sqlpackageAction "DriftReport" -targetServerName $serverName -targetDatabaseName $databaseName -targetUser $sqlUsername -targetPassword $sqlPassword -targetConnectionString $connectionString -outputPath $outputXmlPath -additionalArguments $sqlpackageAdditionalArguments -token $token
$sqlpackageArguments = Get-SqlPackageCommandArguments -authenticationType $authenticationType -sqlpackageAction "DriftReport" -targetServerName $serverName -targetDatabaseName $databaseName -targetUser $sqlUsername -targetPassword $sqlPassword -targetConnectionString $connectionString -outputPath $effectiveOutputPath -additionalArguments $sqlpackageAdditionalArguments -token $token

$sqlpackageArgumentsToBeLogged = Get-SqlPackageCommandArguments -authenticationType $authenticationType -sqlpackageAction "DriftReport" -targetServerName $serverName -targetDatabaseName $databaseName -targetUser $sqlUsername -targetPassword $sqlPassword -targetConnectionString $connectionString -outputPath $outputXmlPath -additionalArguments $sqlpackageAdditionalArguments -isOutputSecure -token $token
$sqlpackageArgumentsToBeLogged = Get-SqlPackageCommandArguments -authenticationType $authenticationType -sqlpackageAction "DriftReport" -targetServerName $serverName -targetDatabaseName $databaseName -targetUser $sqlUsername -targetPassword $sqlPassword -targetConnectionString $connectionString -outputPath $effectiveOutputPath -additionalArguments $sqlpackageAdditionalArguments -isOutputSecure -token $token

Execute-SqlPackage -sqlpackageArguments $sqlpackageArguments -sqlpackageArgumentsToBeLogged $sqlpackageArgumentsToBeLogged

Expand Down Expand Up @@ -156,11 +190,14 @@ function Script-Action {
$publishProfilePath = Find-SqlFiles -filePathPattern $publishProfile -verboseMessage (Get-VstsLocString -Key "SAD_PublishProfilePath") -throwIfMultipleFilesOrNoFilePresent
}

$outputSqlPath = "$ENV:SYSTEM_DEFAULTWORKINGDIRECTORY\GeneratedOutputFiles\${databaseName}_Script.sql"
$defaultOutputSqlPath = "$ENV:SYSTEM_DEFAULTWORKINGDIRECTORY\GeneratedOutputFiles\${databaseName}_Script.sql"
$outputPathResult = Get-EffectiveOutputPath -defaultOutputPath $defaultOutputSqlPath -additionalArguments $sqlpackageAdditionalArguments
$effectiveOutputPath = $outputPathResult.EffectiveOutputPath
$outputSqlPath = $outputPathResult.ResolvedFilePath

$sqlpackageArguments = Get-SqlPackageCommandArguments -authenticationType $authenticationType -sqlpackageAction "Script" -sourceFile $dacpacFilePath -publishProfile $publishProfilePath -targetServerName $serverName -targetDatabaseName $databaseName -targetUser $sqlUsername -targetPassword $sqlPassword -targetConnectionString $connectionString -outputPath $outputSqlPath -additionalArguments $sqlpackageAdditionalArguments -token $token
$sqlpackageArguments = Get-SqlPackageCommandArguments -authenticationType $authenticationType -sqlpackageAction "Script" -sourceFile $dacpacFilePath -publishProfile $publishProfilePath -targetServerName $serverName -targetDatabaseName $databaseName -targetUser $sqlUsername -targetPassword $sqlPassword -targetConnectionString $connectionString -outputPath $effectiveOutputPath -additionalArguments $sqlpackageAdditionalArguments -token $token

$sqlpackageArgumentsToBeLogged = Get-SqlPackageCommandArguments -authenticationType $authenticationType -sqlpackageAction "Script" -sourceFile $dacpacFilePath -publishProfile $publishProfilePath -targetServerName $serverName -targetDatabaseName $databaseName -targetUser $sqlUsername -targetPassword $sqlPassword -targetConnectionString $connectionString -outputPath $outputSqlPath -additionalArguments $sqlpackageAdditionalArguments -isOutputSecure -token $token
$sqlpackageArgumentsToBeLogged = Get-SqlPackageCommandArguments -authenticationType $authenticationType -sqlpackageAction "Script" -sourceFile $dacpacFilePath -publishProfile $publishProfilePath -targetServerName $serverName -targetDatabaseName $databaseName -targetUser $sqlUsername -targetPassword $sqlPassword -targetConnectionString $connectionString -outputPath $effectiveOutputPath -additionalArguments $sqlpackageAdditionalArguments -isOutputSecure -token $token

Execute-SqlPackage -sqlpackageArguments $sqlpackageArguments -sqlpackageArgumentsToBeLogged $sqlpackageArgumentsToBeLogged

Expand Down
4 changes: 4 additions & 0 deletions Tasks/SqlAzureDacpacDeploymentV1/Tests/L0.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ describe('SqlAzureDacpacDeployment - SqlAzureActions Suite', function () {
it ('Validate helper methods', (done) => {
psr.run(path.join(__dirname, 'L0SqlAzureActionsUtilityTests.ps1'), done);
});

it ('Validate Get-EffectiveOutputPath with feature flag and user /OutputPath', (done) => {
psr.run(path.join(__dirname, 'L0GetEffectiveOutputPath.ps1'), done);
});
}
});

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
[CmdletBinding()]
param()

. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1
. $PSScriptRoot\MockVariable.ps1

$ENV:SYSTEM_DEFAULTWORKINGDIRECTORY = "C:\DefaultWorkingDirectory"

Register-Mock Get-VstsPipelineFeature { return $true }
. $PSScriptRoot\..\SqlAzureActions.ps1

$defaultPath = "C:\DefaultWorkingDirectory\GeneratedOutputFiles\TestDatabase_DriftReport.xml"

$featureFlags.enableUserOutputPath = $false
$result = Get-EffectiveOutputPath -defaultOutputPath $defaultPath -additionalArguments '/SomeOtherArg /OutputPath:"C:\Custom\out.xml"'
Assert-AreEqual $defaultPath $result.EffectiveOutputPath "Feature flag off: EffectiveOutputPath should be default"
Assert-AreEqual $defaultPath $result.ResolvedFilePath "Feature flag off: ResolvedFilePath should be default"

$featureFlags.enableUserOutputPath = $true
$result = Get-EffectiveOutputPath -defaultOutputPath $defaultPath -additionalArguments '/SomeOtherArg /AnotherArg:value'
Assert-AreEqual $defaultPath $result.EffectiveOutputPath "No /OutputPath: EffectiveOutputPath should be default"
Assert-AreEqual $defaultPath $result.ResolvedFilePath "No /OutputPath: ResolvedFilePath should be default"

$featureFlags.enableUserOutputPath = $true
$result = Get-EffectiveOutputPath -defaultOutputPath $defaultPath -additionalArguments '/OutputPath:C:\Custom\out.xml'
Assert-AreEqual $null $result.EffectiveOutputPath "Colon unquoted: EffectiveOutputPath should be null"
Assert-AreEqual 'C:\Custom\out.xml' $result.ResolvedFilePath "Colon unquoted: ResolvedFilePath should be user path"

$featureFlags.enableUserOutputPath = $true
$result = Get-EffectiveOutputPath -defaultOutputPath $defaultPath -additionalArguments '/OutputPath:"C:\My Custom Path\out.xml"'
Assert-AreEqual $null $result.EffectiveOutputPath "Colon quoted: EffectiveOutputPath should be null"
Assert-AreEqual 'C:\My Custom Path\out.xml' $result.ResolvedFilePath "Colon quoted: ResolvedFilePath should be user path with spaces"

$featureFlags.enableUserOutputPath = $true
$result = Get-EffectiveOutputPath -defaultOutputPath $defaultPath -additionalArguments '/OutputPath=C:\Custom\out.xml'
Assert-AreEqual $defaultPath $result.EffectiveOutputPath "Equals syntax: EffectiveOutputPath should be default (not detected)"
Assert-AreEqual $defaultPath $result.ResolvedFilePath "Equals syntax: ResolvedFilePath should be default (not detected)"

$featureFlags.enableUserOutputPath = $true
$result = Get-EffectiveOutputPath -defaultOutputPath $defaultPath -additionalArguments '/outputpath:"C:\My Path\out.xml"'
Assert-AreEqual $null $result.EffectiveOutputPath "Case insensitive: EffectiveOutputPath should be null"
Assert-AreEqual 'C:\My Path\out.xml' $result.ResolvedFilePath "Case insensitive: ResolvedFilePath should be user path"

$featureFlags.enableUserOutputPath = $true
Assert-Throws {
Get-EffectiveOutputPath -defaultOutputPath $defaultPath -additionalArguments '/OutputPath:""'
} -MessagePattern "*User-provided /OutputPath is empty or invalid*"

$featureFlags.enableUserOutputPath = $true
$result = Get-EffectiveOutputPath -defaultOutputPath $defaultPath -additionalArguments ''
Assert-AreEqual $defaultPath $result.EffectiveOutputPath "Empty args: EffectiveOutputPath should be default"
Assert-AreEqual $defaultPath $result.ResolvedFilePath "Empty args: ResolvedFilePath should be default"

$featureFlags.enableUserOutputPath = $true
$result = Get-EffectiveOutputPath -defaultOutputPath $defaultPath -additionalArguments $null
Assert-AreEqual $defaultPath $result.EffectiveOutputPath "Null args: EffectiveOutputPath should be default"
Assert-AreEqual $defaultPath $result.ResolvedFilePath "Null args: ResolvedFilePath should be default"

$featureFlags.enableUserOutputPath = $true
$result = Get-EffectiveOutputPath -defaultOutputPath $defaultPath -additionalArguments '/TargetTimeout:120 /OutputPath:"D:\Reports\deploy.xml" /Verbose'
Assert-AreEqual $null $result.EffectiveOutputPath "Mixed args: EffectiveOutputPath should be null"
Assert-AreEqual 'D:\Reports\deploy.xml' $result.ResolvedFilePath "Mixed args: ResolvedFilePath should be user path"

$featureFlags.enableUserOutputPath = $true
$result = Get-EffectiveOutputPath -defaultOutputPath $defaultPath -additionalArguments '/OutputPath : "C:\Spaced\out.xml"'
Assert-AreEqual $null $result.EffectiveOutputPath "Spaces around colon: EffectiveOutputPath should be null"
Assert-AreEqual 'C:\Spaced\out.xml' $result.ResolvedFilePath "Spaces around colon: ResolvedFilePath should be user path"
2 changes: 1 addition & 1 deletion Tasks/SqlAzureDacpacDeploymentV1/task.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"author": "Microsoft Corporation",
"version": {
"Major": 1,
"Minor": 272,
"Minor": 273,
"Patch": 0
},
"demands": [
Expand Down
2 changes: 1 addition & 1 deletion Tasks/SqlAzureDacpacDeploymentV1/task.loc.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"author": "Microsoft Corporation",
"version": {
"Major": 1,
"Minor": 272,
"Minor": 273,
"Patch": 0
},
"demands": [
Expand Down