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
2 changes: 1 addition & 1 deletion changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [1.17.0] - 2026-07-01
### Fixed
* Further fixes of `DeleteNotInSource` with deserialization issue #480
* `Publish-AdfV2FromJson` no longer silently continues after errors: config path errors (ADFT0010) and deployment failures (e.g. Azure Policy blocks) now propagate as terminating errors to the caller #472

## [1.16.0] - 2026-05-27
### Fixed
* `DeleteNotInSource` no longer fails with "Unable to deserialize the response" when ADF contains object types unsupported by the installed Az.DataFactory module version - REST API fallback added to `Get-AdfFromService` #480 #473


## [1.15.0] - 2026-05-26
### Added
* Credential type of ADF objects is now supported for deployment via REST API
Expand Down
2 changes: 1 addition & 1 deletion private/Deploy-AdfObject.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ function Deploy-AdfObject {
if ($adf.PublishOptions.IgnoreLackOfReferencedObject -eq $true) {
Write-Warning "ADFT0006: Referenced object [$type].[$name] was not found. No error raised as user wanted to carry on."
} else {
Write-Error "ADFT0005: Referenced object [$type].[$name] was not found."
throw "ADFT0005: Referenced object [$type].[$name] was not found."
}
} elseif ($type -notin [AdfObject]::IgnoreTypes) {
Deploy-AdfObject -obj $depobj
Expand Down
4 changes: 2 additions & 2 deletions private/Deploy-AdfObjectOnly.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ function Deploy-AdfObjectOnly {
-Force | Out-Null
}
else {
Write-Error "ADFT0012: Deployment for this kind of Integration Runtime is not supported yet."
throw "ADFT0012: Deployment for this kind of Integration Runtime is not supported yet."
}
}
'linkedService'
Expand Down Expand Up @@ -155,7 +155,7 @@ function Deploy-AdfObjectOnly {
}
default
{
Write-Error "ADFT0013: Type $($obj.Type) is not supported."
throw "ADFT0013: Type $($obj.Type) is not supported."
}
}

Expand Down
4 changes: 2 additions & 2 deletions private/Update-PropertiesFromFile.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ function Update-PropertiesFromFile {
if ($option.FailsWhenConfigItemNotFound -eq $false) {
Write-Warning "Could not find object: $type.$name, skipping..."
} else {
Write-Error -Message "ADFT0007: Could not find object: $type.$name"
throw "ADFT0007: Could not find object: $type.$name"
}
} else {
Write-Verbose "- Performing: $action for object(path): $type.$name(properties.$path)"
Expand Down Expand Up @@ -131,7 +131,7 @@ function Update-PropertiesForObject {
Write-Warning "Wrong path defined in config for object(path): $type.$name(properties.$path), skipping..."
} else {
$exc = ([System.Data.DataException]::new("ADFT0010: Wrong path defined in config for object(path): $type.$name(properties.$path)"))
Write-Error -Exception $exc
throw $exc
}
}

Expand Down
8 changes: 4 additions & 4 deletions public/Publish-AdfV2FromJson.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -272,16 +272,16 @@ function Publish-AdfV2FromJson {
$adf.Factories[0].ToBeDeployed = $false
}
}
$adf.AllObjects() | ForEach-Object {
Deploy-AdfObject -obj $_
foreach ($obj in $adf.AllObjects()) {
Deploy-AdfObject -obj $obj
}

Write-Host "===================================================================================";
Write-Host "STEP: Deleting objects not in source ..."
if ($opt.DeleteNotInSource -eq $true) {
$adfIns = Get-AdfFromService -FactoryName "$DataFactoryName" -ResourceGroupName "$ResourceGroupName"
$adfIns.AllObjects() | ForEach-Object {
Remove-AdfObjectIfNotInSource -adfSource $adf -adfTargetObj $_ -adfInstance $adfIns
foreach ($targetObj in $adfIns.AllObjects()) {
Remove-AdfObjectIfNotInSource -adfSource $adf -adfTargetObj $targetObj -adfInstance $adfIns
}
Write-Host "Deleted $($adf.DeletedObjectNames.Count) objects from ADF service."
} else {
Expand Down
141 changes: 141 additions & 0 deletions test/Publish-AdfV2FromJson-ErrorHandling.Tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
BeforeDiscovery {
$ModuleRootPath = $PSScriptRoot | Split-Path -Parent
$moduleManifestName = 'azure.datafactory.tools.psd1'
$moduleManifestPath = Join-Path -Path $ModuleRootPath -ChildPath $moduleManifestName
Import-Module -Name $moduleManifestPath -Force -Verbose:$false
}

InModuleScope azure.datafactory.tools {
$testHelperPath = $PSScriptRoot | Join-Path -ChildPath 'TestHelper'
Import-Module -Name $testHelperPath -Force

$script:SrcFolder = "$PSScriptRoot\BigFactorySample2"
$script:TmpFolder = (New-TemporaryDirectory).FullName
$script:RootFolder = Join-Path -Path $script:TmpFolder -ChildPath (Split-Path -Path $script:SrcFolder -Leaf)
Copy-Item -Path "$SrcFolder" -Destination "$TmpFolder" -Filter "*.*" -Recurse:$true -Force

AfterAll {
Remove-Item -Path $script:TmpFolder -Recurse -Force -ErrorAction SilentlyContinue
}

# -------------------------------------------------------------------------
# Issue #472 – Scenario 1: wrong property path in config (ADFT0010)
#
# config-c004-wrongpath.csv contains "typeProperties:baseUrl" (colon
# separator instead of dot), which causes Write-Error "ADFT0010" inside
# Update-PropertiesForObject. The error is non-terminating, so the
# ForEach-Object loop in Update-PropertiesFromFile swallows it and
# Publish-AdfV2FromJson continues to print "deployed successfully".
#
# Expected fix: the error must propagate as a terminating error so the
# caller observes a failure regardless of $ErrorActionPreference scope.
# -------------------------------------------------------------------------
Describe 'Publish-AdfV2FromJson - Error propagation for wrong config path (Issue #472)' -Tag 'Unit' {

Context 'When stage config has a wrong property path and FailsWhenPathNotFound is true (default)' {

It 'Should throw when Publish-AdfV2FromJson is called with -DryRun' {
# BUG REPRODUCTION: currently does NOT throw (Write-Error is swallowed).
# After fix this test must pass.
$o = New-AdfPublishOption
# FailsWhenPathNotFound defaults to $true
{
Publish-AdfV2FromJson `
-RootFolder $script:RootFolder `
-ResourceGroupName 'rg-test' `
-DataFactoryName 'adf-test' `
-Stage 'c004-wrongpath' `
-Option $o `
-DryRun
} | Should -Throw
}
}

Context 'When stage config has a wrong property path and FailsWhenPathNotFound is false' {

It 'Should not throw (wrong path is only a warning)' {
$o = New-AdfPublishOption
$o.FailsWhenPathNotFound = $false
{
Publish-AdfV2FromJson `
-RootFolder $script:RootFolder `
-ResourceGroupName 'rg-test' `
-DataFactoryName 'adf-test' `
-Stage 'c004-wrongpath' `
-Option $o `
-DryRun
} | Should -Not -Throw
}
}
}

# -------------------------------------------------------------------------
# Issue #472 – Scenario 2: ADF object deployment fails at runtime
#
# When Deploy-AdfObjectOnly emits a non-terminating Write-Error (e.g. an
# Azure Policy block: "RequestDisallowedByPolicy"), the ForEach-Object
# pipeline in Publish-AdfV2FromJson absorbs the error and the function
# continues to report "deployed successfully".
#
# Expected fix: the deployment loop must propagate errors so the function
# terminates and the caller sees a failure.
# -------------------------------------------------------------------------
Describe 'Publish-AdfV2FromJson - Error propagation for deployment failure (Issue #472)' -Tag 'Unit' {

Context 'When an ADF object deployment produces a terminating error' {

BeforeAll {
Mock Get-AzDataFactoryV2 {
[PSCustomObject]@{ Name = 'adf-test'; ResourceGroupName = 'rg-test' }
}
# Azure cmdlets (e.g. New-AzResource) throw terminating errors for
# serious failures like Azure Policy blocks. In PowerShell 5.1 the
# ForEach-Object pipeline was absorbing these terminating errors and
# allowing the loop to continue, so the function reported success.
# The fix replaces ForEach-Object with a foreach statement, which
# propagates terminating errors correctly in all PS versions.
Mock Deploy-AdfObjectOnly {
throw 'Simulated: RequestDisallowedByPolicy - resource was disallowed by policy'
}
}

It 'Should throw when any object deployment fails' {
# BUG REPRODUCTION: previously did NOT throw because ForEach-Object
# absorbed the terminating error in PS 5.1.
# After fix (foreach loop) this test must pass.
$o = New-AdfPublishOption
$o.StopStartTriggers = $false
$o.DeleteNotInSource = $false
{
Publish-AdfV2FromJson `
-RootFolder $script:RootFolder `
-ResourceGroupName 'rg-test' `
-DataFactoryName 'adf-test' `
-Option $o
} | Should -Throw
}

It 'Should throw even when the caller has not set $ErrorActionPreference to Stop' {
# BUG REPRODUCTION: the module scope isolates $ErrorActionPreference
# from the caller's script scope, so setting it externally has no effect.
# The fix must make the function fail independently of the caller's EAP.
$o = New-AdfPublishOption
$o.StopStartTriggers = $false
$o.DeleteNotInSource = $false
$threw = $false
# Deliberately NOT using Should -Throw so Pester does not alter EAP
try {
Publish-AdfV2FromJson `
-RootFolder $script:RootFolder `
-ResourceGroupName 'rg-test' `
-DataFactoryName 'adf-test' `
-Option $o
}
catch {
$threw = $true
}
$threw | Should -BeTrue -Because 'deployment failures must propagate to the caller'
}
}
}
}