From 72509b1a80a489ae6cd00942769da5d24ad9f294 Mon Sep 17 00:00:00 2001 From: Kamil Nowinski Date: Thu, 20 Mar 2025 01:27:38 +0000 Subject: [PATCH 01/12] Fixed format of RequiredModules (again!) --- azure.datafactory.tools.psd1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/azure.datafactory.tools.psd1 b/azure.datafactory.tools.psd1 index d600efe..cbb1f80 100644 --- a/azure.datafactory.tools.psd1 +++ b/azure.datafactory.tools.psd1 @@ -53,12 +53,12 @@ # Modules that must be imported into the global environment prior to importing this module RequiredModules = @( @{ - ModuleName = 'Az.Resources' - ModuleVersion = '6.5.0' + ModuleName = 'Az.Resources'; + ModuleVersion = '6.5.0'; }, @{ - ModuleName = 'Az.DataFactory' - ModuleVersion = '1.16.0' + ModuleName = 'Az.DataFactory'; + ModuleVersion = '1.16.0'; } ) From 7a3866554f6e02d83a5362d66710044c01d5df08 Mon Sep 17 00:00:00 2001 From: Kamil Nowinski Date: Tue, 26 May 2026 22:48:13 +0100 Subject: [PATCH 02/12] Starting blob event trigger fails with 'Resource cannot be updated during provisioning' - now waits for provisioning to complete before retrying #484 --- azure.datafactory.tools.psd1 | 4 ++-- changelog.md | 17 +++++++++++++++++ private/Start-Trigger.ps1 | 30 +++++++++++++++++++++++++----- test/Start-Trigger.Tests.ps1 | 30 +++++++++++++++++++++++++----- 4 files changed, 69 insertions(+), 12 deletions(-) diff --git a/azure.datafactory.tools.psd1 b/azure.datafactory.tools.psd1 index cbb1f80..1a2ac84 100644 --- a/azure.datafactory.tools.psd1 +++ b/azure.datafactory.tools.psd1 @@ -12,7 +12,7 @@ RootModule = 'azure.datafactory.tools.psm1' # Version number of this module. - ModuleVersion = '1.12.0' + ModuleVersion = '1.15.0' # Supported PSEditions # CompatiblePSEditions = @() @@ -27,7 +27,7 @@ CompanyName = 'SQLPlayer' # Copyright statement for this module - Copyright = '(c) 2020-2025 Kamil Nowinski. All rights reserved.' + Copyright = '(c) 2020-2026 Kamil Nowinski. All rights reserved.' # Description of the functionality provided by this module Description = 'PowerShell module to help with CI&CD for Azure Data Factory, mainly to publish to ADF service in multiple environments. Check https://github.com/Azure-Player/azure.datafactory.tools/ & https://azureplayer.net/adf/' diff --git a/changelog.md b/changelog.md index fc06184..32ad796 100644 --- a/changelog.md +++ b/changelog.md @@ -4,6 +4,23 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## [1.15.0] - 2026-05-26 +### Fixed +* Starting blob event trigger fails with 'Resource cannot be updated during provisioning' - now waits for provisioning to complete before retrying #484, #474, #463 + +## [1.14.0] - 2025-10-24 +### Added +* New input parameters for Get-AdfDocDiagram function: Include, Exclude. + +## [1.13.1] - 2025-10-19 +### Fixed +* Fixed trigger start retry logic to exit immediately on successful start instead of running all 5 attempts #465 +* Fixed CSV parametrization line count reporting when CSV contains empty lines #446 + +## [1.13.0] - 2025-05-20 +### Fixed +* Adopted to breaking change in Az.Accounts v5.0 with Get-AzAccessToken that doesn't support String anymore #449 + ## [1.12.0] - 2025-03-20 ### Added * Error during the import when required Az.Resource module is not loaded #336 diff --git a/private/Start-Trigger.ps1 b/private/Start-Trigger.ps1 index 12df010..7299028 100644 --- a/private/Start-Trigger.ps1 +++ b/private/Start-Trigger.ps1 @@ -19,17 +19,37 @@ function Start-Trigger { -DataFactoryName $DataFactoryName ` -Name $Name ` -Force | Out-Null + break } catch { + $errMsg = $_.Exception.Message if ($i -lt $attempts) { - Write-Verbose "Attempt #$i of starting trigger failed. Retry in 2 seconds." - Start-Sleep -Seconds 2 - } - else + if ($errMsg -like "*cannot be updated during provisioning*") { + Write-Verbose "Attempt #${i}: Trigger '$Name' is still provisioning. Waiting for provisioning to complete..." + $provisioningTimeout = 300 + $pollInterval = 10 + $elapsed = 0 + while ($elapsed -lt $provisioningTimeout) { + Start-Sleep -Seconds $pollInterval + $elapsed += $pollInterval + $trigger = Get-AzDataFactoryV2Trigger ` + -ResourceGroupName $ResourceGroupName ` + -DataFactoryName $DataFactoryName ` + -Name $Name + $provState = $trigger.Properties.ProvisioningState + Write-Verbose "Trigger provisioning state: $provState ($elapsed sec elapsed)" + if ($provState -ne 'Provisioning') { break } + } + } else { + Write-Verbose "Attempt #$i of starting trigger failed. Retry in 2 seconds." + Start-Sleep -Seconds 2 + } + } + else { Write-Host "Failed starting trigger after $attempts attempts." - Write-Warning -Message $_.Exception.Message + Write-Warning -Message $errMsg } } } diff --git a/test/Start-Trigger.Tests.ps1 b/test/Start-Trigger.Tests.ps1 index 6e203ee..b3d8186 100644 --- a/test/Start-Trigger.Tests.ps1 +++ b/test/Start-Trigger.Tests.ps1 @@ -25,18 +25,38 @@ InModuleScope azure.datafactory.tools { It 'Should retry after the first failure' { $script:attempts = 2 - Mock Start-AzDataFactoryV2Trigger { $attempts--; if ($attempts -eq 0) { Write-Host 'OK' } else { Write-Error 'BadRequest' } } - Start-Trigger -ResourceGroupName 'rg' -DataFactoryName 'adf' -Name 'tr1' + Mock Start-AzDataFactoryV2Trigger { $attempts--; if ($attempts -eq 0) { Write-Host 'OK' } else { throw 'BadRequest' } } + Start-Trigger -ResourceGroupName 'rg' -DataFactoryName 'adf' -Name 'tr1' Assert-MockCalled Start-AzDataFactoryV2Trigger -Times 2 } It 'Should retry max 5 times when failure' { - Mock Start-AzDataFactoryV2Trigger { Write-Error 'BadRequest' } - Start-Trigger -ResourceGroupName 'rg' -DataFactoryName 'adf' -Name 'tr1' + Mock Start-AzDataFactoryV2Trigger { throw 'BadRequest' } + Start-Trigger -ResourceGroupName 'rg' -DataFactoryName 'adf' -Name 'tr1' Assert-MockCalled Start-AzDataFactoryV2Trigger -Times 5 } - } + It 'Should wait for provisioning and retry when trigger cannot be updated during provisioning' { + $script:startAttempt = 0 + Mock Start-AzDataFactoryV2Trigger { + $script:startAttempt++ + if ($script:startAttempt -eq 1) { throw 'BadRequest: Resource cannot be updated during provisioning' } + } + $script:getAttempt = 0 + Mock Get-AzDataFactoryV2Trigger { + $script:getAttempt++ + $state = if ($script:getAttempt -eq 1) { 'Provisioning' } else { 'Succeeded' } + return [PSCustomObject]@{ Properties = [PSCustomObject]@{ ProvisioningState = $state } } + } + Mock Start-Sleep {} + + Start-Trigger -ResourceGroupName 'rg' -DataFactoryName 'adf' -Name 'tr1' + + Assert-MockCalled Start-AzDataFactoryV2Trigger -Times 2 + Assert-MockCalled Get-AzDataFactoryV2Trigger -Times 2 + } + + } } From c808ea72994de12825e30ced3c35df36539b17ef Mon Sep 17 00:00:00 2001 From: Kamil Nowinski Date: Tue, 26 May 2026 22:57:43 +0100 Subject: [PATCH 03/12] CI workload updated --- .github/workflows/develop-ci.yml | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/.github/workflows/develop-ci.yml b/.github/workflows/develop-ci.yml index be52900..b589da8 100644 --- a/.github/workflows/develop-ci.yml +++ b/.github/workflows/develop-ci.yml @@ -1,38 +1,35 @@ -# This is a basic workflow to help you get started with Actions - name: CI -# Controls when the workflow will run on: - # Triggers the workflow on push or pull request events but only for the master branch push: branches: [ develop ] pull_request: branches: [ develop ] - - # Allows you to run this workflow manually from the Actions tab workflow_dispatch: -# A workflow run is made up of one or more jobs that can run sequentially or in parallel +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: build: - runs-on: windows-2019 + runs-on: windows-latest - # Steps represent a sequence of tasks that will be executed as part of the job steps: - - # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Login via Az module - uses: azure/login@v1 + uses: azure/login@v2 with: - creds: ${{secrets.AZURE_CREDENTIALS}} - enable-AzPSSession: true + creds: ${{ secrets.AZURE_CREDENTIALS }} + enable-AzPSSession: true - name: Run Azure PowerShell script - uses: azure/powershell@v1 + uses: azure/powershell@v2 with: inlineScript: | - test/!RunAllTests.ps1 -folder 'D:/a/azure.datafactory.tools/azure.datafactory.tools/' -TestFilenameFilter "*" + test/!RunAllTests.ps1 -folder '${{ github.workspace }}/' -TestFilenameFilter "*" azPSVersion: "latest" From 26ae9d8e8827c1674317afd20e68f6b36cee5f4c Mon Sep 17 00:00:00 2001 From: Kamil Nowinski Date: Tue, 26 May 2026 23:03:24 +0100 Subject: [PATCH 04/12] InstallModules = true --- .github/workflows/develop-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/develop-ci.yml b/.github/workflows/develop-ci.yml index b589da8..0d21218 100644 --- a/.github/workflows/develop-ci.yml +++ b/.github/workflows/develop-ci.yml @@ -31,5 +31,5 @@ jobs: uses: azure/powershell@v2 with: inlineScript: | - test/!RunAllTests.ps1 -folder '${{ github.workspace }}/' -TestFilenameFilter "*" + test/!RunAllTests.ps1 -folder '${{ github.workspace }}/' -TestFilenameFilter "*" -InstallModules azPSVersion: "latest" From 337522451bc0867a77de79ad871ce233a654f797 Mon Sep 17 00:00:00 2001 From: Kamil Nowinski Date: Tue, 26 May 2026 23:57:54 +0100 Subject: [PATCH 05/12] Credentials --- changelog.md | 6 ++ private/Deploy-AdfObjectOnly.ps1 | 12 ++- private/Get-AzDFV2Credential.ps1 | 3 +- private/Remove-AdfObjectRestAPI.ps1 | 3 +- test/Get-AzDFV2Credential.Tests.ps1 | 112 +++++++++++++++++++++++++ test/Publish-AdfV2FromJson-1.Tests.ps1 | 11 +++ test/TestHelper/TestHelper.psm1 | 3 + 7 files changed, 146 insertions(+), 4 deletions(-) create mode 100644 test/Get-AzDFV2Credential.Tests.ps1 diff --git a/changelog.md b/changelog.md index 32ad796..583b6f5 100644 --- a/changelog.md +++ b/changelog.md @@ -5,8 +5,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [1.15.0] - 2026-05-26 + +### Added + +* Credential type of ADF objects is now supported for deployment via REST API + ### Fixed * Starting blob event trigger fails with 'Resource cannot be updated during provisioning' - now waits for provisioning to complete before retrying #484, #474, #463 +* Fixed REST API calls failing with 401 Unauthorized due to Az.Accounts 5.x returning SecureString from Get-AzAccessToken ## [1.14.0] - 2025-10-24 ### Added diff --git a/private/Deploy-AdfObjectOnly.ps1 b/private/Deploy-AdfObjectOnly.ps1 index d583d25..1398035 100644 --- a/private/Deploy-AdfObjectOnly.ps1 +++ b/private/Deploy-AdfObjectOnly.ps1 @@ -123,8 +123,16 @@ function Deploy-AdfObjectOnly { } 'credential' { - Write-Warning "Credentials are not yet supported. The deployment for the object is skipped." - Write-Warning "Any reference to the object causes error, unless to deploy it before." + $resType = Get-AzureResourceType $obj.Type + $resName = $obj.AzureResourceName() + + New-AzResource ` + -ResourceType $resType ` + -ResourceGroupName $ResourceGroupName ` + -ResourceName "$resName" ` + -ApiVersion "2018-06-01" ` + -Properties $json ` + -IsFullObject -Force | Out-Null } 'AzResource' { diff --git a/private/Get-AzDFV2Credential.ps1 b/private/Get-AzDFV2Credential.ps1 index 0fd6624..67f7c56 100644 --- a/private/Get-AzDFV2Credential.ps1 +++ b/private/Get-AzDFV2Credential.ps1 @@ -7,9 +7,10 @@ function Get-AzDFV2Credential { # Retrieve all credentials via API without parsing $token = Get-AzAccessToken -ResourceUrl 'https://management.azure.com' + $tokenStr = [System.Net.NetworkCredential]::new('', $token.Token).Password $authHeader = @{ 'Content-Type' = 'application/json' - 'Authorization' = 'Bearer ' + $token.Token + 'Authorization' = 'Bearer ' + $tokenStr } $url = "https://management.azure.com$($adfi.DataFactoryId)/credentials?api-version=2018-06-01" diff --git a/private/Remove-AdfObjectRestAPI.ps1 b/private/Remove-AdfObjectRestAPI.ps1 index 290f928..50c1150 100644 --- a/private/Remove-AdfObjectRestAPI.ps1 +++ b/private/Remove-AdfObjectRestAPI.ps1 @@ -9,9 +9,10 @@ function Remove-AdfObjectRestAPI { Write-Debug "BEGIN: Remove-AdfObjectRestAPI()" $token = Get-AzAccessToken -ResourceUrl 'https://management.azure.com' + $tokenStr = [System.Net.NetworkCredential]::new('', $token.Token).Password $authHeader = @{ 'Content-Type' = 'application/json' - 'Authorization' = 'Bearer ' + $token.Token + 'Authorization' = 'Bearer ' + $tokenStr } $url = "https://management.azure.com$($adfInstance.Id)/$type_plural/$($name)?api-version=2018-06-01" diff --git a/test/Get-AzDFV2Credential.Tests.ps1 b/test/Get-AzDFV2Credential.Tests.ps1 new file mode 100644 index 0000000..ac71268 --- /dev/null +++ b/test/Get-AzDFV2Credential.Tests.ps1 @@ -0,0 +1,112 @@ +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 + + Describe 'Get-AzDFV2Credential' -Tag 'Unit' { + + It 'Should exist' { + { Get-Command -Name Get-AzDFV2Credential -ErrorAction Stop } | Should -Not -Throw + } + + Context 'When the API returns no credentials' { + BeforeEach { + $script:adfi = [PSCustomObject]@{ DataFactoryId = '/subscriptions/sub-123/resourceGroups/rg/providers/Microsoft.DataFactory/factories/adf1' } + + Mock Get-AzAccessToken { + return [PSCustomObject]@{ Token = 'fake-token-abc' } + } + Mock Invoke-RestMethod { + return [PSCustomObject]@{ value = @() } + } + } + + It 'Should return an empty list' { + $result = Get-AzDFV2Credential -adfi $script:adfi + @($result).Count | Should -Be 0 + } + + It 'Should call Get-AzAccessToken once' { + Get-AzDFV2Credential -adfi $script:adfi + Assert-MockCalled Get-AzAccessToken -Times 1 -Exactly + } + + It 'Should call Invoke-RestMethod with Bearer token in Authorization header' { + Get-AzDFV2Credential -adfi $script:adfi + Assert-MockCalled Invoke-RestMethod -Times 1 -Exactly -ParameterFilter { + $Headers['Authorization'] -eq 'Bearer fake-token-abc' + } + } + + It 'Should call Invoke-RestMethod with correct credentials URL' { + Get-AzDFV2Credential -adfi $script:adfi + Assert-MockCalled Invoke-RestMethod -Times 1 -Exactly -ParameterFilter { + $Uri -eq "https://management.azure.com$($script:adfi.DataFactoryId)/credentials?api-version=2018-06-01" + } + } + + It 'Should call Invoke-RestMethod using GET method' { + Get-AzDFV2Credential -adfi $script:adfi + Assert-MockCalled Invoke-RestMethod -Times 1 -Exactly -ParameterFilter { + $Method -eq 'GET' + } + } + } + + Context 'When the API returns multiple credentials' { + BeforeEach { + $script:adfi = [PSCustomObject]@{ DataFactoryId = '/subscriptions/sub-123/resourceGroups/rg/providers/Microsoft.DataFactory/factories/adf1' } + + $cred1 = [PSCustomObject]@{ name = 'cred1'; type = 'Microsoft.DataFactory/factories/credentials'; properties = @{} } + $cred2 = [PSCustomObject]@{ name = 'cred2'; type = 'Microsoft.DataFactory/factories/credentials'; properties = @{} } + + Mock Get-AzAccessToken { + return [PSCustomObject]@{ Token = 'fake-token-abc' } + } + Mock Invoke-RestMethod { + return [PSCustomObject]@{ value = @($cred1, $cred2) } + } + } + + It 'Should return all credentials as AdfPSCredential objects' { + $result = Get-AzDFV2Credential -adfi $script:adfi + $result.Count | Should -Be 2 + $result | ForEach-Object { $_.GetType().Name | Should -Be 'AdfPSCredential' } + } + + It 'Should populate the Name property from the API response' { + $result = Get-AzDFV2Credential -adfi $script:adfi + $result[0].Name | Should -Be 'cred1' + $result[1].Name | Should -Be 'cred2' + } + + It 'Should populate the Child property with the raw API object' { + $result = Get-AzDFV2Credential -adfi $script:adfi + $result[0].Child.name | Should -Be 'cred1' + $result[1].Child.name | Should -Be 'cred2' + } + } + + Context 'When Invoke-RestMethod throws' { + BeforeEach { + $script:adfi = [PSCustomObject]@{ DataFactoryId = '/subscriptions/sub-123/resourceGroups/rg/providers/Microsoft.DataFactory/factories/adf1' } + + Mock Get-AzAccessToken { + return [PSCustomObject]@{ Token = 'fake-token-abc' } + } + Mock Invoke-RestMethod { throw 'Unauthorized' } + } + + It 'Should propagate the error' { + { Get-AzDFV2Credential -adfi $script:adfi } | Should -Throw + } + } + } +} diff --git a/test/Publish-AdfV2FromJson-1.Tests.ps1 b/test/Publish-AdfV2FromJson-1.Tests.ps1 index 8bd6aec..d9df0d9 100644 --- a/test/Publish-AdfV2FromJson-1.Tests.ps1 +++ b/test/Publish-AdfV2FromJson-1.Tests.ps1 @@ -34,6 +34,17 @@ InModuleScope azure.datafactory.tools { -Location $script:Location -DataFactoryName $script:DataFactoryName -Option $o } + It 'adf2 Should deploy credential1 to ADF service' { + $script:RootFolder = Join-Path $PSScriptRoot "adf2" + $o = New-AdfPublishOption + $o.StopStartTriggers = $false + $o.Includes.Add("credential.credential1", "") + Publish-AdfV2FromJson -RootFolder $script:RootFolder -ResourceGroupName $script:ResourceGroupName ` + -Location $script:Location -DataFactoryName $script:DataFactoryName -Option $o + $adfIns = Get-AdfFromService -FactoryName $script:DataFactoryName -ResourceGroupName $script:ResourceGroupName + $adfIns.Credentials | Where-Object { $_.Name -eq 'credential1' } | Should -Not -BeNullOrEmpty + } + } } diff --git a/test/TestHelper/TestHelper.psm1 b/test/TestHelper/TestHelper.psm1 index e92bc68..b116f50 100644 --- a/test/TestHelper/TestHelper.psm1 +++ b/test/TestHelper/TestHelper.psm1 @@ -226,6 +226,9 @@ function Get-TargetEnv { SrcFolder = "$rootPath\$AdfOrigName" } $c = Get-AzContext + if ($null -eq $c) { + throw "No active Azure context found. Run Connect-AzAccount before executing integration tests." + } $guid = $c.Subscription.Id.Substring(0,8) $target.DataFactoryName = $AdfOrigName + "-$guid" return $target From 3ff0aae84c1cae00f6483da08ee41b748a2f215c Mon Sep 17 00:00:00 2001 From: Kamil Nowinski Date: Wed, 27 May 2026 00:33:49 +0100 Subject: [PATCH 06/12] Add Pester test result publishing and update permissions in CI workflow --- .github/workflows/develop-ci.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/develop-ci.yml b/.github/workflows/develop-ci.yml index 0d21218..99b39c1 100644 --- a/.github/workflows/develop-ci.yml +++ b/.github/workflows/develop-ci.yml @@ -9,6 +9,7 @@ on: permissions: contents: read + checks: write # required by test-reporter concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -27,9 +28,17 @@ jobs: creds: ${{ secrets.AZURE_CREDENTIALS }} enable-AzPSSession: true - - name: Run Azure PowerShell script + - name: Run All Unit and Integration Tests uses: azure/powershell@v2 with: inlineScript: | test/!RunAllTests.ps1 -folder '${{ github.workspace }}/' -TestFilenameFilter "*" -InstallModules azPSVersion: "latest" + + - name: Publish Pester Test Results + uses: dorny/test-reporter@v1 + if: always() # run even when tests fail + with: + name: Pester Tests + path: TEST-Results.xml + reporter: java-junit # NUnit XML is compatible with this reporter From eb40d75f776591869a50fa524a0d9786580e6d70 Mon Sep 17 00:00:00 2001 From: Kamil Nowinski Date: Wed, 27 May 2026 00:44:22 +0100 Subject: [PATCH 07/12] Path of result file missing? --- .github/workflows/develop-ci.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/develop-ci.yml b/.github/workflows/develop-ci.yml index 99b39c1..125fe45 100644 --- a/.github/workflows/develop-ci.yml +++ b/.github/workflows/develop-ci.yml @@ -32,13 +32,14 @@ jobs: uses: azure/powershell@v2 with: inlineScript: | - test/!RunAllTests.ps1 -folder '${{ github.workspace }}/' -TestFilenameFilter "*" -InstallModules + test/!RunAllTests.ps1 -folder '${{ github.workspace }}/' -TestFilenameFilter "Get*" -InstallModules:$false azPSVersion: "latest" - name: Publish Pester Test Results - uses: dorny/test-reporter@v1 - if: always() # run even when tests fail + uses: dorny/test-reporter@v3 + if: ${{ !cancelled() }} # run this step even if previous step failed with: name: Pester Tests - path: TEST-Results.xml + path: 'TEST-*.xml,**/TEST-*.xml' reporter: java-junit # NUnit XML is compatible with this reporter + collapsed: 'auto' From 4757ae0ebe6c0da1401b96e9fb7840830f0673f1 Mon Sep 17 00:00:00 2001 From: Kamil Nowinski Date: Wed, 27 May 2026 00:49:02 +0100 Subject: [PATCH 08/12] reporter: dotnet-nunit --- .github/workflows/develop-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/develop-ci.yml b/.github/workflows/develop-ci.yml index 125fe45..1e4945f 100644 --- a/.github/workflows/develop-ci.yml +++ b/.github/workflows/develop-ci.yml @@ -41,5 +41,5 @@ jobs: with: name: Pester Tests path: 'TEST-*.xml,**/TEST-*.xml' - reporter: java-junit # NUnit XML is compatible with this reporter + reporter: dotnet-nunit # NUnit XML is compatible with this reporter collapsed: 'auto' From 1e0f74a5da36f7a135ef75be85edffa425bf8b57 Mon Sep 17 00:00:00 2001 From: Kamil Nowinski Date: Wed, 27 May 2026 00:51:52 +0100 Subject: [PATCH 09/12] JUnitXml --- .github/workflows/develop-ci.yml | 2 +- test/!RunAllTests.ps1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/develop-ci.yml b/.github/workflows/develop-ci.yml index 1e4945f..125fe45 100644 --- a/.github/workflows/develop-ci.yml +++ b/.github/workflows/develop-ci.yml @@ -41,5 +41,5 @@ jobs: with: name: Pester Tests path: 'TEST-*.xml,**/TEST-*.xml' - reporter: dotnet-nunit # NUnit XML is compatible with this reporter + reporter: java-junit # NUnit XML is compatible with this reporter collapsed: 'auto' diff --git a/test/!RunAllTests.ps1 b/test/!RunAllTests.ps1 index 4ffe0ef..b463a39 100644 --- a/test/!RunAllTests.ps1 +++ b/test/!RunAllTests.ps1 @@ -70,7 +70,7 @@ try { $configuration.Run.Exit = $true $configuration.Should.ErrorAction = 'Continue' $configuration.CodeCoverage.Enabled = $false - $configuration.TestResult.OutputFormat = "NUnitXml" + $configuration.TestResult.OutputFormat = "JUnitXml" $configuration.TestResult.OutputPath = "$folder\TEST-Results.xml" $configuration.TestResult.Enabled = $true $configuration.Output.Verbosity = 'Detailed' From 2cf8d09a5faf242e23921264afa24506cf62987f Mon Sep 17 00:00:00 2001 From: Kamil Nowinski Date: Wed, 27 May 2026 01:07:58 +0100 Subject: [PATCH 10/12] Fixed credential tests --- .github/workflows/develop-ci.yml | 6 +++--- private/Get-AzDFV2Credential.ps1 | 2 +- test/!RunAllTests.ps1 | 3 +++ test/Get-AzDFV2Credential.Tests.ps1 | 27 +++++++++++++-------------- 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/.github/workflows/develop-ci.yml b/.github/workflows/develop-ci.yml index 125fe45..7093944 100644 --- a/.github/workflows/develop-ci.yml +++ b/.github/workflows/develop-ci.yml @@ -32,7 +32,7 @@ jobs: uses: azure/powershell@v2 with: inlineScript: | - test/!RunAllTests.ps1 -folder '${{ github.workspace }}/' -TestFilenameFilter "Get*" -InstallModules:$false + test/!RunAllTests.ps1 -folder '${{ github.workspace }}/' -TestFilenameFilter "Get*" -InstallModules:$false -ResultOutputFormat "JUnitXml" azPSVersion: "latest" - name: Publish Pester Test Results @@ -40,6 +40,6 @@ jobs: if: ${{ !cancelled() }} # run this step even if previous step failed with: name: Pester Tests - path: 'TEST-*.xml,**/TEST-*.xml' - reporter: java-junit # NUnit XML is compatible with this reporter + path: '**/TEST-*.xml' + reporter: java-junit collapsed: 'auto' diff --git a/private/Get-AzDFV2Credential.ps1 b/private/Get-AzDFV2Credential.ps1 index a98fb2c..c0cffad 100644 --- a/private/Get-AzDFV2Credential.ps1 +++ b/private/Get-AzDFV2Credential.ps1 @@ -21,7 +21,7 @@ function Get-AzDFV2Credential { return $null } - [System.Collections.ArrayList] $items = @{} + [System.Collections.ArrayList] $items = @() ($r.Content | ConvertFrom-Json).value | ForEach-Object { $i = [AdfPSCredential]::New($_); $items.Add($i) | Out-Null; } Write-Debug "END: Get-AzDFV2Credential()" diff --git a/test/!RunAllTests.ps1 b/test/!RunAllTests.ps1 index b463a39..ba01f7c 100644 --- a/test/!RunAllTests.ps1 +++ b/test/!RunAllTests.ps1 @@ -8,6 +8,9 @@ Param( [Parameter(Mandatory=$false)] [Switch]$MajorRelease, + [Parameter(Mandatory=$false)] + [string]$ResultOutputFormat = "NUnitXml", + [Parameter(Mandatory=$true)] [Switch]$InstallModules ) diff --git a/test/Get-AzDFV2Credential.Tests.ps1 b/test/Get-AzDFV2Credential.Tests.ps1 index ac71268..2b80afd 100644 --- a/test/Get-AzDFV2Credential.Tests.ps1 +++ b/test/Get-AzDFV2Credential.Tests.ps1 @@ -23,8 +23,8 @@ InModuleScope azure.datafactory.tools { Mock Get-AzAccessToken { return [PSCustomObject]@{ Token = 'fake-token-abc' } } - Mock Invoke-RestMethod { - return [PSCustomObject]@{ value = @() } + Mock Invoke-AzRestMethod { + return [PSCustomObject]@{ StatusCode = 200; Content = '{"value":[]}' } } } @@ -38,23 +38,21 @@ InModuleScope azure.datafactory.tools { Assert-MockCalled Get-AzAccessToken -Times 1 -Exactly } - It 'Should call Invoke-RestMethod with Bearer token in Authorization header' { + It 'Should call Invoke-AzRestMethod once' { Get-AzDFV2Credential -adfi $script:adfi - Assert-MockCalled Invoke-RestMethod -Times 1 -Exactly -ParameterFilter { - $Headers['Authorization'] -eq 'Bearer fake-token-abc' - } + Assert-MockCalled Invoke-AzRestMethod -Times 1 -Exactly } - It 'Should call Invoke-RestMethod with correct credentials URL' { + It 'Should call Invoke-AzRestMethod with correct credentials URL' { Get-AzDFV2Credential -adfi $script:adfi - Assert-MockCalled Invoke-RestMethod -Times 1 -Exactly -ParameterFilter { + Assert-MockCalled Invoke-AzRestMethod -Times 1 -Exactly -ParameterFilter { $Uri -eq "https://management.azure.com$($script:adfi.DataFactoryId)/credentials?api-version=2018-06-01" } } - It 'Should call Invoke-RestMethod using GET method' { + It 'Should call Invoke-AzRestMethod using GET method' { Get-AzDFV2Credential -adfi $script:adfi - Assert-MockCalled Invoke-RestMethod -Times 1 -Exactly -ParameterFilter { + Assert-MockCalled Invoke-AzRestMethod -Times 1 -Exactly -ParameterFilter { $Method -eq 'GET' } } @@ -66,12 +64,13 @@ InModuleScope azure.datafactory.tools { $cred1 = [PSCustomObject]@{ name = 'cred1'; type = 'Microsoft.DataFactory/factories/credentials'; properties = @{} } $cred2 = [PSCustomObject]@{ name = 'cred2'; type = 'Microsoft.DataFactory/factories/credentials'; properties = @{} } + $script:credJson = @{ value = @($cred1, $cred2) } | ConvertTo-Json -Depth 5 Mock Get-AzAccessToken { return [PSCustomObject]@{ Token = 'fake-token-abc' } } - Mock Invoke-RestMethod { - return [PSCustomObject]@{ value = @($cred1, $cred2) } + Mock Invoke-AzRestMethod { + return [PSCustomObject]@{ StatusCode = 200; Content = $script:credJson } } } @@ -94,14 +93,14 @@ InModuleScope azure.datafactory.tools { } } - Context 'When Invoke-RestMethod throws' { + Context 'When Invoke-AzRestMethod throws' { BeforeEach { $script:adfi = [PSCustomObject]@{ DataFactoryId = '/subscriptions/sub-123/resourceGroups/rg/providers/Microsoft.DataFactory/factories/adf1' } Mock Get-AzAccessToken { return [PSCustomObject]@{ Token = 'fake-token-abc' } } - Mock Invoke-RestMethod { throw 'Unauthorized' } + Mock Invoke-AzRestMethod { throw 'Unauthorized' } } It 'Should propagate the error' { From a2554888e74f87b39fdc08d53be492fd20241b60 Mon Sep 17 00:00:00 2001 From: Kamil Nowinski Date: Wed, 27 May 2026 01:11:59 +0100 Subject: [PATCH 11/12] Updated all three actions to their Node.js 24-compatible versions --- .github/workflows/develop-ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/develop-ci.yml b/.github/workflows/develop-ci.yml index 7093944..fe156bb 100644 --- a/.github/workflows/develop-ci.yml +++ b/.github/workflows/develop-ci.yml @@ -20,16 +20,16 @@ jobs: runs-on: windows-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Login via Az module - uses: azure/login@v2 + uses: azure/login@v3 with: creds: ${{ secrets.AZURE_CREDENTIALS }} enable-AzPSSession: true - name: Run All Unit and Integration Tests - uses: azure/powershell@v2 + uses: azure/powershell@v3 with: inlineScript: | test/!RunAllTests.ps1 -folder '${{ github.workspace }}/' -TestFilenameFilter "Get*" -InstallModules:$false -ResultOutputFormat "JUnitXml" From 2919e3ec2287c8e196bda0776f0d3cdce86fb074 Mon Sep 17 00:00:00 2001 From: Kamil Nowinski Date: Wed, 27 May 2026 01:14:02 +0100 Subject: [PATCH 12/12] Run all tests --- .github/workflows/develop-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/develop-ci.yml b/.github/workflows/develop-ci.yml index fe156bb..942fb9a 100644 --- a/.github/workflows/develop-ci.yml +++ b/.github/workflows/develop-ci.yml @@ -32,7 +32,7 @@ jobs: uses: azure/powershell@v3 with: inlineScript: | - test/!RunAllTests.ps1 -folder '${{ github.workspace }}/' -TestFilenameFilter "Get*" -InstallModules:$false -ResultOutputFormat "JUnitXml" + test/!RunAllTests.ps1 -folder '${{ github.workspace }}/' -TestFilenameFilter "*" -InstallModules:$false -ResultOutputFormat "JUnitXml" azPSVersion: "latest" - name: Publish Pester Test Results