From 66ace180b759cf87636062fc7476a0ffa65b4f94 Mon Sep 17 00:00:00 2001 From: Alastair Pitts Date: Thu, 27 Nov 2025 13:07:08 +1100 Subject: [PATCH 01/22] Remove net462 as a target framework from all projects --- source/Calamari.Aws/Calamari.Aws.csproj | 4 +- source/Calamari.Azure/Calamari.Azure.csproj | 4 +- .../Calamari.AzureAppService.Tests.csproj | 4 +- .../Calamari.AzureAppService.csproj | 4 +- .../Calamari.AzureResourceGroup.Tests.csproj | 4 +- .../Calamari.AzureResourceGroup.csproj | 4 +- .../Calamari.AzureScripting.Tests.csproj | 8 ++-- .../Calamari.AzureScripting.csproj | 11 ++---- .../Calamari.AzureServiceFabric.Tests.csproj | 4 +- .../Calamari.AzureServiceFabric.csproj | 4 +- .../Calamari.AzureWebApp.Tests.csproj | 9 +++-- .../Calamari.AzureWebApp.csproj | 15 +++---- .../Calamari.CloudAccounts.csproj | 8 +--- source/Calamari.Common/Calamari.Common.csproj | 26 ++----------- ...ari.ConsolidateCalamariPackages.Api.csproj | 2 +- ...i.ConsolidateCalamariPackages.Tests.csproj | 1 + ...alamari.ConsolidateCalamariPackages.csproj | 2 +- .../CalamariPackages.cs | 1 + .../Calamari.GoogleCloudAccounts.csproj | 9 +---- ...Calamari.GoogleCloudScripting.Tests.csproj | 4 +- .../Calamari.GoogleCloudScripting.csproj | 4 +- .../Calamari.Scripting.Tests.csproj | 2 +- .../Calamari.Scripting.csproj | 10 ++--- source/Calamari.Shared/Calamari.Shared.csproj | 38 ++---------------- .../Calamari.Terraform.Tests.csproj | 4 +- .../Calamari.Terraform.csproj | 4 +- .../Calamari.Testing/Calamari.Testing.csproj | 12 ++---- source/Calamari.Tests/Calamari.Tests.csproj | 39 ++++--------------- source/Calamari/Calamari.csproj | 32 ++------------- 29 files changed, 78 insertions(+), 195 deletions(-) diff --git a/source/Calamari.Aws/Calamari.Aws.csproj b/source/Calamari.Aws/Calamari.Aws.csproj index a60f95341f..5dc7adfff2 100644 --- a/source/Calamari.Aws/Calamari.Aws.csproj +++ b/source/Calamari.Aws/Calamari.Aws.csproj @@ -1,7 +1,6 @@  1.0.0.0 - Exe anycpu Calamari.Aws Library @@ -19,7 +18,8 @@ Calamari.Aws.exe.manifest - net462;netstandard2.1 + netstandard2.1 + 10 true diff --git a/source/Calamari.Azure/Calamari.Azure.csproj b/source/Calamari.Azure/Calamari.Azure.csproj index 9e67e43391..f2c8c1e7d1 100644 --- a/source/Calamari.Azure/Calamari.Azure.csproj +++ b/source/Calamari.Azure/Calamari.Azure.csproj @@ -6,8 +6,8 @@ Octopus Deploy Octopus Deploy Pty Ltd win-x64;linux-x64;osx-x64;linux-arm;linux-arm64 - 8.0 - net462;net8.0 + 10.0 + net8.0 true diff --git a/source/Calamari.AzureAppService.Tests/Calamari.AzureAppService.Tests.csproj b/source/Calamari.AzureAppService.Tests/Calamari.AzureAppService.Tests.csproj index 3369377f7e..084ca3d3fd 100644 --- a/source/Calamari.AzureAppService.Tests/Calamari.AzureAppService.Tests.csproj +++ b/source/Calamari.AzureAppService.Tests/Calamari.AzureAppService.Tests.csproj @@ -5,8 +5,8 @@ Calamari.AzureAppService.Tests false win-x64;linux-x64;osx-x64;linux-arm;linux-arm64 - 8.0 - net462;net8.0 + 10.0 + net8.0 true diff --git a/source/Calamari.AzureAppService/Calamari.AzureAppService.csproj b/source/Calamari.AzureAppService/Calamari.AzureAppService.csproj index e1c0d185a4..df3c06e547 100644 --- a/source/Calamari.AzureAppService/Calamari.AzureAppService.csproj +++ b/source/Calamari.AzureAppService/Calamari.AzureAppService.csproj @@ -7,9 +7,9 @@ true Exe win-x64;linux-x64;osx-x64;linux-arm;linux-arm64 - 8.0 + 10.0 NU5104 - net462;net8.0 + net8.0 true diff --git a/source/Calamari.AzureResourceGroup.Tests/Calamari.AzureResourceGroup.Tests.csproj b/source/Calamari.AzureResourceGroup.Tests/Calamari.AzureResourceGroup.Tests.csproj index 15226288c6..2e35535f4a 100644 --- a/source/Calamari.AzureResourceGroup.Tests/Calamari.AzureResourceGroup.Tests.csproj +++ b/source/Calamari.AzureResourceGroup.Tests/Calamari.AzureResourceGroup.Tests.csproj @@ -4,7 +4,8 @@ Calamari.AzureResourceGroup.Tests false win-x64;linux-x64;osx-x64;linux-arm;linux-arm64 - net462;net8.0 + net8.0 + 10 true @@ -13,7 +14,6 @@ - diff --git a/source/Calamari.AzureResourceGroup/Calamari.AzureResourceGroup.csproj b/source/Calamari.AzureResourceGroup/Calamari.AzureResourceGroup.csproj index d637a549e1..5cb6c0bd0b 100644 --- a/source/Calamari.AzureResourceGroup/Calamari.AzureResourceGroup.csproj +++ b/source/Calamari.AzureResourceGroup/Calamari.AzureResourceGroup.csproj @@ -2,13 +2,13 @@ Calamari.AzureResourceGroup Calamari.AzureResourceGroup - 8 + 10 enable Exe false false win-x64;linux-x64;osx-x64;linux-arm;linux-arm64 - net462;net8.0 + net8.0 diff --git a/source/Calamari.AzureScripting.Tests/Calamari.AzureScripting.Tests.csproj b/source/Calamari.AzureScripting.Tests/Calamari.AzureScripting.Tests.csproj index cc004f8bfd..ea995d90b1 100644 --- a/source/Calamari.AzureScripting.Tests/Calamari.AzureScripting.Tests.csproj +++ b/source/Calamari.AzureScripting.Tests/Calamari.AzureScripting.Tests.csproj @@ -3,11 +3,11 @@ Calamari.AzureScripting.Tests Calamari.AzureScripting.Tests - 8 + 10 enable win-x64;linux-x64;osx-x64;linux-arm;linux-arm64 false - net462;net8.0 + net8.0 true @@ -20,6 +20,7 @@ + @@ -50,7 +51,4 @@ - - - diff --git a/source/Calamari.AzureScripting/Calamari.AzureScripting.csproj b/source/Calamari.AzureScripting/Calamari.AzureScripting.csproj index 1079789115..ba65fdb0ba 100644 --- a/source/Calamari.AzureScripting/Calamari.AzureScripting.csproj +++ b/source/Calamari.AzureScripting/Calamari.AzureScripting.csproj @@ -2,14 +2,14 @@ Calamari.AzureScripting Calamari.AzureScripting - 8 + 10 enable Exe true win-x64;linux-x64;osx-x64;linux-arm;linux-arm64 true false - net462;net8.0 + net8.0 true @@ -17,9 +17,10 @@ - + + @@ -27,10 +28,6 @@ - - - - diff --git a/source/Calamari.AzureServiceFabric.Tests/Calamari.AzureServiceFabric.Tests.csproj b/source/Calamari.AzureServiceFabric.Tests/Calamari.AzureServiceFabric.Tests.csproj index 16eb7cbbe0..78e9ff2d12 100644 --- a/source/Calamari.AzureServiceFabric.Tests/Calamari.AzureServiceFabric.Tests.csproj +++ b/source/Calamari.AzureServiceFabric.Tests/Calamari.AzureServiceFabric.Tests.csproj @@ -4,9 +4,9 @@ Calamari.AzureServiceFabric.Tests Calamari.AzureServiceFabric.Tests false - net462;net8.0-windows + net8.0-windows win-x64 - 8.0 + 10.0 true diff --git a/source/Calamari.AzureServiceFabric/Calamari.AzureServiceFabric.csproj b/source/Calamari.AzureServiceFabric/Calamari.AzureServiceFabric.csproj index 7fd1cb589f..819cd43f67 100644 --- a/source/Calamari.AzureServiceFabric/Calamari.AzureServiceFabric.csproj +++ b/source/Calamari.AzureServiceFabric/Calamari.AzureServiceFabric.csproj @@ -5,9 +5,9 @@ true false Exe - net462;net8.0-windows + net8.0-windows win-x64 - 8.0 + 10.0 true diff --git a/source/Calamari.AzureWebApp.Tests/Calamari.AzureWebApp.Tests.csproj b/source/Calamari.AzureWebApp.Tests/Calamari.AzureWebApp.Tests.csproj index 08873b7c92..035e926791 100644 --- a/source/Calamari.AzureWebApp.Tests/Calamari.AzureWebApp.Tests.csproj +++ b/source/Calamari.AzureWebApp.Tests/Calamari.AzureWebApp.Tests.csproj @@ -2,9 +2,9 @@ Calamari.AzureWebApp.Tests Calamari.AzureWebApp.Tests - net462;net8.0 + net8.0 win-x64 - 8.0 + 10.0 false true @@ -27,15 +27,16 @@ - + + - + diff --git a/source/Calamari.AzureWebApp/Calamari.AzureWebApp.csproj b/source/Calamari.AzureWebApp/Calamari.AzureWebApp.csproj index 91a6c6ad47..532f6098c2 100644 --- a/source/Calamari.AzureWebApp/Calamari.AzureWebApp.csproj +++ b/source/Calamari.AzureWebApp/Calamari.AzureWebApp.csproj @@ -8,6 +8,9 @@ net462;net8.0 win-x64;linux-x64;osx-x64;linux-arm;linux-arm64 8.0 + net8.0 + win-x64 + 10.0 true @@ -26,11 +29,7 @@ - - - - - + netcoreshim true @@ -56,13 +55,15 @@ - + + + - + diff --git a/source/Calamari.CloudAccounts/Calamari.CloudAccounts.csproj b/source/Calamari.CloudAccounts/Calamari.CloudAccounts.csproj index 1b6fc438a5..ebe9789ecd 100644 --- a/source/Calamari.CloudAccounts/Calamari.CloudAccounts.csproj +++ b/source/Calamari.CloudAccounts/Calamari.CloudAccounts.csproj @@ -2,7 +2,8 @@ Calamari.CloudAccounts - net462;netstandard2.1 + netstandard2.1 + 8 Octopus.Calamari.CloudAccounts Calamari.CloudAccounts Octopus Deploy @@ -13,11 +14,6 @@ git - - - - - diff --git a/source/Calamari.Common/Calamari.Common.csproj b/source/Calamari.Common/Calamari.Common.csproj index 59002bb728..f4038b0fdf 100644 --- a/source/Calamari.Common/Calamari.Common.csproj +++ b/source/Calamari.Common/Calamari.Common.csproj @@ -1,7 +1,7 @@  - net462;netstandard2.1 + netstandard2.1 8 enable anycpu @@ -13,36 +13,16 @@ https://github.com/OctopusDeploy/Calamari/ https://github.com/OctopusDeploy/Calamari/blob/main/LICENSE.txt - - $(DefineConstants);USE_ALPHAFS_FOR_LONG_FILE_PATH_SUPPORT;HAS_SSL3 - - + $(DefineConstants);USE_NUGET_V3_LIBS;WORKAROUND_FOR_EMPTY_STRING_BUG;HAS_NULLABLE_REF_TYPES - - CS8600;CS8601;CS8602;CS8603;CS8604;NU5104 - - - + - - - - - - - - - - - - - diff --git a/source/Calamari.ConsolidateCalamariPackages.Api/Calamari.ConsolidateCalamariPackages.Api.csproj b/source/Calamari.ConsolidateCalamariPackages.Api/Calamari.ConsolidateCalamariPackages.Api.csproj index 3bea38be8a..8ece508ed7 100644 --- a/source/Calamari.ConsolidateCalamariPackages.Api/Calamari.ConsolidateCalamariPackages.Api.csproj +++ b/source/Calamari.ConsolidateCalamariPackages.Api/Calamari.ConsolidateCalamariPackages.Api.csproj @@ -6,7 +6,7 @@ net8.0 enable enable - default + 10 Octopus Deploy Octopus Deploy Pty Ltd diff --git a/source/Calamari.ConsolidateCalamariPackages.Tests/Calamari.ConsolidateCalamariPackages.Tests.csproj b/source/Calamari.ConsolidateCalamariPackages.Tests/Calamari.ConsolidateCalamariPackages.Tests.csproj index 3b0e227376..471a082843 100644 --- a/source/Calamari.ConsolidateCalamariPackages.Tests/Calamari.ConsolidateCalamariPackages.Tests.csproj +++ b/source/Calamari.ConsolidateCalamariPackages.Tests/Calamari.ConsolidateCalamariPackages.Tests.csproj @@ -2,6 +2,7 @@ net8.0 + 10 false true diff --git a/source/Calamari.ConsolidateCalamariPackages/Calamari.ConsolidateCalamariPackages.csproj b/source/Calamari.ConsolidateCalamariPackages/Calamari.ConsolidateCalamariPackages.csproj index cec3a1dc67..51ec557c00 100644 --- a/source/Calamari.ConsolidateCalamariPackages/Calamari.ConsolidateCalamariPackages.csproj +++ b/source/Calamari.ConsolidateCalamariPackages/Calamari.ConsolidateCalamariPackages.csproj @@ -4,7 +4,7 @@ Octopus.Calamari.ConsolidatedPackage Octopus.Calamari.ConsolidatedPackage net8.0 - default + 10 true true Octopus Deploy diff --git a/source/Calamari.ConsolidateCalamariPackages/CalamariPackages.cs b/source/Calamari.ConsolidateCalamariPackages/CalamariPackages.cs index e8fcaac811..c83563c968 100644 --- a/source/Calamari.ConsolidateCalamariPackages/CalamariPackages.cs +++ b/source/Calamari.ConsolidateCalamariPackages/CalamariPackages.cs @@ -10,6 +10,7 @@ public static class CalamariPackages public static readonly List CrossPlatformFlavours = new() { + "Calamari", "Calamari.AzureAppService", "Calamari.AzureResourceGroup", "Calamari.GoogleCloudScripting", diff --git a/source/Calamari.GoogleCloudAccounts/Calamari.GoogleCloudAccounts.csproj b/source/Calamari.GoogleCloudAccounts/Calamari.GoogleCloudAccounts.csproj index 1126f5d78a..eedc4cd7fe 100644 --- a/source/Calamari.GoogleCloudAccounts/Calamari.GoogleCloudAccounts.csproj +++ b/source/Calamari.GoogleCloudAccounts/Calamari.GoogleCloudAccounts.csproj @@ -2,18 +2,13 @@ Calamari.GoogleCloudAccounts - net462;netstandard2.1 - latest + netstandard2.1 + 8 CS8632 true - - - - - diff --git a/source/Calamari.GoogleCloudScripting.Tests/Calamari.GoogleCloudScripting.Tests.csproj b/source/Calamari.GoogleCloudScripting.Tests/Calamari.GoogleCloudScripting.Tests.csproj index f1e08445dc..a56af599cc 100644 --- a/source/Calamari.GoogleCloudScripting.Tests/Calamari.GoogleCloudScripting.Tests.csproj +++ b/source/Calamari.GoogleCloudScripting.Tests/Calamari.GoogleCloudScripting.Tests.csproj @@ -3,10 +3,10 @@ Calamari.GoogleCloudScripting.Tests win-x64;linux-x64;osx-x64;linux-arm;linux-arm64 - 8 + 10 false enable - net462;net8.0 + net8.0 true diff --git a/source/Calamari.GoogleCloudScripting/Calamari.GoogleCloudScripting.csproj b/source/Calamari.GoogleCloudScripting/Calamari.GoogleCloudScripting.csproj index 3a2216edae..3d40942ae6 100644 --- a/source/Calamari.GoogleCloudScripting/Calamari.GoogleCloudScripting.csproj +++ b/source/Calamari.GoogleCloudScripting/Calamari.GoogleCloudScripting.csproj @@ -4,10 +4,10 @@ Calamari.GoogleCloudScripting Exe win-x64;linux-x64;osx-x64;linux-arm;linux-arm64 - 8 + 10 false false - net462;net8.0 + net8.0 CS8632 true diff --git a/source/Calamari.Scripting.Tests/Calamari.Scripting.Tests.csproj b/source/Calamari.Scripting.Tests/Calamari.Scripting.Tests.csproj index e6954b932c..a9c2dae2f1 100644 --- a/source/Calamari.Scripting.Tests/Calamari.Scripting.Tests.csproj +++ b/source/Calamari.Scripting.Tests/Calamari.Scripting.Tests.csproj @@ -5,7 +5,7 @@ net8.0 win-x64;linux-x64;osx-x64;linux-arm;linux-arm64 false - default + 10 true diff --git a/source/Calamari.Scripting/Calamari.Scripting.csproj b/source/Calamari.Scripting/Calamari.Scripting.csproj index 1ce4bfecdc..55840e02ec 100644 --- a/source/Calamari.Scripting/Calamari.Scripting.csproj +++ b/source/Calamari.Scripting/Calamari.Scripting.csproj @@ -7,8 +7,8 @@ enable win-x64;linux-x64;osx-x64;linux-arm;linux-arm64 true - 9 - net462;net8.0 + 10 + net8.0 true @@ -19,11 +19,7 @@ - - - CS8600;CS8601;CS8602;CS8603;CS8604 - - + $(DefineConstants);HAS_NULLABLE_REF_TYPES diff --git a/source/Calamari.Shared/Calamari.Shared.csproj b/source/Calamari.Shared/Calamari.Shared.csproj index 2cb6e18649..f1af098f91 100644 --- a/source/Calamari.Shared/Calamari.Shared.csproj +++ b/source/Calamari.Shared/Calamari.Shared.csproj @@ -21,20 +21,13 @@ Calamari - 8 + 10 enable - net462;netstandard2.1 + netstandard2.1 - - $(DefineConstants);NETFX;USE_NUGET_V2_LIBS;USE_OCTODIFF_EXE; - anycpu - - + $(DefineConstants);USE_NUGET_V3_LIBS - - CS8600;CS8601;CS8602;CS8603;CS8604;DE0003;DE0004 - @@ -56,8 +49,6 @@ - - @@ -68,29 +59,6 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/source/Calamari.Terraform.Tests/Calamari.Terraform.Tests.csproj b/source/Calamari.Terraform.Tests/Calamari.Terraform.Tests.csproj index 033202e388..3a22d11bd1 100644 --- a/source/Calamari.Terraform.Tests/Calamari.Terraform.Tests.csproj +++ b/source/Calamari.Terraform.Tests/Calamari.Terraform.Tests.csproj @@ -5,8 +5,8 @@ Calamari.Terraform.Tests win-x64;linux-x64;osx-x64;linux-arm;linux-arm64 false - 9 - net462;net8.0 + 10 + net8.0 CS8632 true diff --git a/source/Calamari.Terraform/Calamari.Terraform.csproj b/source/Calamari.Terraform/Calamari.Terraform.csproj index f657b522ce..200dad9450 100644 --- a/source/Calamari.Terraform/Calamari.Terraform.csproj +++ b/source/Calamari.Terraform/Calamari.Terraform.csproj @@ -5,9 +5,9 @@ true false Exe - 9 + 10 win-x64;linux-x64;osx-x64;linux-arm;linux-arm64 - net462;net8.0 + net8.0 true diff --git a/source/Calamari.Testing/Calamari.Testing.csproj b/source/Calamari.Testing/Calamari.Testing.csproj index 9c648e29cd..a7d22f6d13 100644 --- a/source/Calamari.Testing/Calamari.Testing.csproj +++ b/source/Calamari.Testing/Calamari.Testing.csproj @@ -4,12 +4,12 @@ enable https://github.com/OctopusDeploy/Calamari/ Apache-2.0 - default - net462;netstandard2.1 + 10 + netstandard2.1 true Octopus.Calamari.Testing - + $(DefineConstants);NETCORE @@ -22,14 +22,10 @@ + - - - - - diff --git a/source/Calamari.Tests/Calamari.Tests.csproj b/source/Calamari.Tests/Calamari.Tests.csproj index ea1518752f..39a7f8fcc5 100644 --- a/source/Calamari.Tests/Calamari.Tests.csproj +++ b/source/Calamari.Tests/Calamari.Tests.csproj @@ -10,17 +10,14 @@ win-x64;linux-x64;osx-x64;linux-arm;linux-arm64 - net462;net8.0 - 8 + net8.0 + 10 true true $(DefineConstants);NETCORE;AZURE_CORE;JAVA_SUPPORT - - $(DefineConstants);NETFX;IIS_SUPPORT;USE_NUGET_V2_LIBS;USE_OCTODIFF_EXE; - all @@ -43,29 +40,10 @@ - - - - - - - - - - - - - - - - - - - @@ -273,15 +251,8 @@ - - - - - @(NuGetCommandLineRef->'%(ResolvedPath)')/tools/*.* - - @@ -292,6 +263,9 @@ + + + @@ -301,5 +275,8 @@ + + + diff --git a/source/Calamari/Calamari.csproj b/source/Calamari/Calamari.csproj index ad3156338e..1a394cfcdb 100644 --- a/source/Calamari/Calamari.csproj +++ b/source/Calamari/Calamari.csproj @@ -18,16 +18,12 @@ Calamari win-x64;linux-x64;osx-x64;linux-arm;linux-arm64 Calamari.exe.manifest - net462;net8.0 - 8 + net8.0 + 10 CS8632 true - - $(DefineConstants);IIS_SUPPORT; - anycpu - $(DefineConstants);DEBUG @@ -61,26 +57,10 @@ - - - - - - - - - - - - - - - - - - + + @@ -89,10 +69,6 @@ PreserveNewest - - - - CS8632 true diff --git a/source/Calamari.AzureWebApp.Tests/Calamari.AzureWebApp.Tests.csproj b/source/Calamari.AzureWebApp.Tests/Calamari.AzureWebApp.Tests.csproj index 035e926791..e35abfbf5a 100644 --- a/source/Calamari.AzureWebApp.Tests/Calamari.AzureWebApp.Tests.csproj +++ b/source/Calamari.AzureWebApp.Tests/Calamari.AzureWebApp.Tests.csproj @@ -4,7 +4,7 @@ Calamari.AzureWebApp.Tests net8.0 win-x64 - 10.0 + default false true diff --git a/source/Calamari.AzureWebApp/Calamari.AzureWebApp.csproj b/source/Calamari.AzureWebApp/Calamari.AzureWebApp.csproj index 532f6098c2..96bf09da75 100644 --- a/source/Calamari.AzureWebApp/Calamari.AzureWebApp.csproj +++ b/source/Calamari.AzureWebApp/Calamari.AzureWebApp.csproj @@ -10,7 +10,7 @@ 8.0 net8.0 win-x64 - 10.0 + default true diff --git a/source/Calamari.CloudAccounts/Calamari.CloudAccounts.csproj b/source/Calamari.CloudAccounts/Calamari.CloudAccounts.csproj index ebe9789ecd..ddcbae89ef 100644 --- a/source/Calamari.CloudAccounts/Calamari.CloudAccounts.csproj +++ b/source/Calamari.CloudAccounts/Calamari.CloudAccounts.csproj @@ -3,7 +3,7 @@ Calamari.CloudAccounts netstandard2.1 - 8 + default Octopus.Calamari.CloudAccounts Calamari.CloudAccounts Octopus Deploy diff --git a/source/Calamari.Common/Calamari.Common.csproj b/source/Calamari.Common/Calamari.Common.csproj index f4038b0fdf..ea2639a439 100644 --- a/source/Calamari.Common/Calamari.Common.csproj +++ b/source/Calamari.Common/Calamari.Common.csproj @@ -2,7 +2,7 @@ netstandard2.1 - 8 + default enable anycpu false diff --git a/source/Calamari.ConsolidateCalamariPackages.Api/Calamari.ConsolidateCalamariPackages.Api.csproj b/source/Calamari.ConsolidateCalamariPackages.Api/Calamari.ConsolidateCalamariPackages.Api.csproj index 8ece508ed7..3bea38be8a 100644 --- a/source/Calamari.ConsolidateCalamariPackages.Api/Calamari.ConsolidateCalamariPackages.Api.csproj +++ b/source/Calamari.ConsolidateCalamariPackages.Api/Calamari.ConsolidateCalamariPackages.Api.csproj @@ -6,7 +6,7 @@ net8.0 enable enable - 10 + default Octopus Deploy Octopus Deploy Pty Ltd diff --git a/source/Calamari.ConsolidateCalamariPackages.Tests/Calamari.ConsolidateCalamariPackages.Tests.csproj b/source/Calamari.ConsolidateCalamariPackages.Tests/Calamari.ConsolidateCalamariPackages.Tests.csproj index 471a082843..d2ff2336b5 100644 --- a/source/Calamari.ConsolidateCalamariPackages.Tests/Calamari.ConsolidateCalamariPackages.Tests.csproj +++ b/source/Calamari.ConsolidateCalamariPackages.Tests/Calamari.ConsolidateCalamariPackages.Tests.csproj @@ -2,7 +2,7 @@ net8.0 - 10 + default false true diff --git a/source/Calamari.GoogleCloudAccounts/Calamari.GoogleCloudAccounts.csproj b/source/Calamari.GoogleCloudAccounts/Calamari.GoogleCloudAccounts.csproj index eedc4cd7fe..0314511fa2 100644 --- a/source/Calamari.GoogleCloudAccounts/Calamari.GoogleCloudAccounts.csproj +++ b/source/Calamari.GoogleCloudAccounts/Calamari.GoogleCloudAccounts.csproj @@ -3,7 +3,7 @@ Calamari.GoogleCloudAccounts netstandard2.1 - 8 + default CS8632 true diff --git a/source/Calamari.GoogleCloudScripting.Tests/Calamari.GoogleCloudScripting.Tests.csproj b/source/Calamari.GoogleCloudScripting.Tests/Calamari.GoogleCloudScripting.Tests.csproj index a56af599cc..a94cce45ed 100644 --- a/source/Calamari.GoogleCloudScripting.Tests/Calamari.GoogleCloudScripting.Tests.csproj +++ b/source/Calamari.GoogleCloudScripting.Tests/Calamari.GoogleCloudScripting.Tests.csproj @@ -3,7 +3,7 @@ Calamari.GoogleCloudScripting.Tests win-x64;linux-x64;osx-x64;linux-arm;linux-arm64 - 10 + default false enable net8.0 diff --git a/source/Calamari.GoogleCloudScripting/Calamari.GoogleCloudScripting.csproj b/source/Calamari.GoogleCloudScripting/Calamari.GoogleCloudScripting.csproj index 3d40942ae6..0beec07bdc 100644 --- a/source/Calamari.GoogleCloudScripting/Calamari.GoogleCloudScripting.csproj +++ b/source/Calamari.GoogleCloudScripting/Calamari.GoogleCloudScripting.csproj @@ -4,7 +4,7 @@ Calamari.GoogleCloudScripting Exe win-x64;linux-x64;osx-x64;linux-arm;linux-arm64 - 10 + default false false net8.0 diff --git a/source/Calamari.Scripting.Tests/Calamari.Scripting.Tests.csproj b/source/Calamari.Scripting.Tests/Calamari.Scripting.Tests.csproj index a9c2dae2f1..e6954b932c 100644 --- a/source/Calamari.Scripting.Tests/Calamari.Scripting.Tests.csproj +++ b/source/Calamari.Scripting.Tests/Calamari.Scripting.Tests.csproj @@ -5,7 +5,7 @@ net8.0 win-x64;linux-x64;osx-x64;linux-arm;linux-arm64 false - 10 + default true diff --git a/source/Calamari.Scripting/Calamari.Scripting.csproj b/source/Calamari.Scripting/Calamari.Scripting.csproj index 55840e02ec..5fe1e153af 100644 --- a/source/Calamari.Scripting/Calamari.Scripting.csproj +++ b/source/Calamari.Scripting/Calamari.Scripting.csproj @@ -7,7 +7,7 @@ enable win-x64;linux-x64;osx-x64;linux-arm;linux-arm64 true - 10 + default net8.0 true diff --git a/source/Calamari.Shared/Calamari.Shared.csproj b/source/Calamari.Shared/Calamari.Shared.csproj index f1af098f91..85226da4c0 100644 --- a/source/Calamari.Shared/Calamari.Shared.csproj +++ b/source/Calamari.Shared/Calamari.Shared.csproj @@ -21,7 +21,7 @@ Calamari - 10 + default enable netstandard2.1 diff --git a/source/Calamari.Terraform.Tests/Calamari.Terraform.Tests.csproj b/source/Calamari.Terraform.Tests/Calamari.Terraform.Tests.csproj index 3a22d11bd1..2f033d36dd 100644 --- a/source/Calamari.Terraform.Tests/Calamari.Terraform.Tests.csproj +++ b/source/Calamari.Terraform.Tests/Calamari.Terraform.Tests.csproj @@ -5,7 +5,7 @@ Calamari.Terraform.Tests win-x64;linux-x64;osx-x64;linux-arm;linux-arm64 false - 10 + default net8.0 CS8632 diff --git a/source/Calamari.Terraform/Calamari.Terraform.csproj b/source/Calamari.Terraform/Calamari.Terraform.csproj index 200dad9450..e3b016bf2a 100644 --- a/source/Calamari.Terraform/Calamari.Terraform.csproj +++ b/source/Calamari.Terraform/Calamari.Terraform.csproj @@ -5,7 +5,7 @@ true false Exe - 10 + default win-x64;linux-x64;osx-x64;linux-arm;linux-arm64 net8.0 true diff --git a/source/Calamari.Testing/Calamari.Testing.csproj b/source/Calamari.Testing/Calamari.Testing.csproj index ff86bb8154..807271bdbe 100644 --- a/source/Calamari.Testing/Calamari.Testing.csproj +++ b/source/Calamari.Testing/Calamari.Testing.csproj @@ -4,7 +4,7 @@ enable https://github.com/OctopusDeploy/Calamari/ Apache-2.0 - 10 + default net8.0 true Octopus.Calamari.Testing diff --git a/source/Calamari.Tests/Calamari.Tests.csproj b/source/Calamari.Tests/Calamari.Tests.csproj index 39a7f8fcc5..2e93d7e47e 100644 --- a/source/Calamari.Tests/Calamari.Tests.csproj +++ b/source/Calamari.Tests/Calamari.Tests.csproj @@ -11,7 +11,7 @@ win-x64;linux-x64;osx-x64;linux-arm;linux-arm64 net8.0 - 10 + default true true diff --git a/source/Calamari/Calamari.csproj b/source/Calamari/Calamari.csproj index 1a394cfcdb..292a770587 100644 --- a/source/Calamari/Calamari.csproj +++ b/source/Calamari/Calamari.csproj @@ -19,7 +19,7 @@ win-x64;linux-x64;osx-x64;linux-arm;linux-arm64 Calamari.exe.manifest net8.0 - 10 + default CS8632 true From 0e17a0d213d1a157bc36811d9caa19d5dccafe6c Mon Sep 17 00:00:00 2001 From: Alastair Pitts Date: Thu, 27 Nov 2025 17:28:43 +1100 Subject: [PATCH 10/22] Change Calamari.Common to .NET 8.0 (from netstandard) --- source/Calamari.Common/Calamari.Common.csproj | 5 +- .../Packages/NuGet/LocalNuGetPackage.cs | 6 +- .../Features/Packages/ZipPackageExtractor.cs | 11 -- .../Features/Processes/CommandLine.cs | 15 +-- .../NullableReferenceTypeAttributes.cs | 50 -------- .../Extensions/EnumerableExtensions.cs | 17 --- .../Extensions/ScriptingEnvironment.cs | 9 -- .../Plumbing/Extensions/VersionExtensions.cs | 6 +- .../FileSystem/CalamariPhysicalFileSystem.cs | 2 - .../Plumbing/FileSystem/FileOperations.cs | 121 ------------------ .../FileSystem/WindowsPhysicalFileSystem.cs | 8 -- .../Plumbing/SecurityProtocols.cs | 12 +- 12 files changed, 15 insertions(+), 247 deletions(-) delete mode 100644 source/Calamari.Common/NullableReferenceTypeAttributes.cs delete mode 100644 source/Calamari.Common/Plumbing/Extensions/EnumerableExtensions.cs diff --git a/source/Calamari.Common/Calamari.Common.csproj b/source/Calamari.Common/Calamari.Common.csproj index ea2639a439..49bfd2c14f 100644 --- a/source/Calamari.Common/Calamari.Common.csproj +++ b/source/Calamari.Common/Calamari.Common.csproj @@ -1,7 +1,7 @@  - netstandard2.1 + net8.0 default enable anycpu @@ -13,9 +13,6 @@ https://github.com/OctopusDeploy/Calamari/ https://github.com/OctopusDeploy/Calamari/blob/main/LICENSE.txt - - $(DefineConstants);USE_NUGET_V3_LIBS;WORKAROUND_FOR_EMPTY_STRING_BUG;HAS_NULLABLE_REF_TYPES - diff --git a/source/Calamari.Common/Features/Packages/NuGet/LocalNuGetPackage.cs b/source/Calamari.Common/Features/Packages/NuGet/LocalNuGetPackage.cs index c161f78730..2d81232a91 100644 --- a/source/Calamari.Common/Features/Packages/NuGet/LocalNuGetPackage.cs +++ b/source/Calamari.Common/Features/Packages/NuGet/LocalNuGetPackage.cs @@ -1,8 +1,4 @@ -#if USE_NUGET_V3_LIBS -using NuGet.Packaging; -#else -using NuGet; -#endif +using NuGet.Packaging; using System; using System.IO; using Calamari.Common.Plumbing; diff --git a/source/Calamari.Common/Features/Packages/ZipPackageExtractor.cs b/source/Calamari.Common/Features/Packages/ZipPackageExtractor.cs index 1ac1ad363c..71d7bbe42c 100644 --- a/source/Calamari.Common/Features/Packages/ZipPackageExtractor.cs +++ b/source/Calamari.Common/Features/Packages/ZipPackageExtractor.cs @@ -32,18 +32,7 @@ public int Extract(string packageFile, string directory) var filesExtracted = 0; using var inStream = new FileStream(packageFile, FileMode.Open, FileAccess.Read); - -#if NETFRAMEWORK - var readerOptions = new ReaderOptions(); - if (forceUtf8ZipFiles) - { - readerOptions.ArchiveEncoding.Forced = System.Text.Encoding.UTF8; - } - - using var archive = ZipArchive.Open(inStream, readerOptions); -#else using var archive = ZipArchive.Open(inStream); -#endif foreach (var entry in archive.Entries) { diff --git a/source/Calamari.Common/Features/Processes/CommandLine.cs b/source/Calamari.Common/Features/Processes/CommandLine.cs index 9834ed6d58..a6e4e3f813 100644 --- a/source/Calamari.Common/Features/Processes/CommandLine.cs +++ b/source/Calamari.Common/Features/Processes/CommandLine.cs @@ -12,7 +12,7 @@ public class CommandLine readonly List args = new List(); string? action; bool useDotnet; - private Dictionary? environmentVariables = null; + private Dictionary? environmentVariables = null; private bool outputToLog = true; private string? workingDirectory; @@ -217,15 +217,14 @@ string Escape(string argValue, bool escapeArg) last -= 1; } -#if WORKAROUND_FOR_EMPTY_STRING_BUG -// linux under bash on netcore empty "" gets eaten, hand "\0" -// which gets through as a null string - if(argValue == "") - argValue = "\0"; -#endif + // linux under bash on netcore empty "" gets eaten, hand "\0" + // which gets through as a null string + if (argValue == "") + argValue = "\0"; + // Double-quotes are always escaped. return "\"" + argValue.Replace("\"", "\\\"") + "\""; } } } -} +} \ No newline at end of file diff --git a/source/Calamari.Common/NullableReferenceTypeAttributes.cs b/source/Calamari.Common/NullableReferenceTypeAttributes.cs deleted file mode 100644 index 27fc1f8187..0000000000 --- a/source/Calamari.Common/NullableReferenceTypeAttributes.cs +++ /dev/null @@ -1,50 +0,0 @@ -#if !HAS_NULLABLE_REF_TYPES -using System; - -/// -/// These attributes replicate the ones from System.Diagnostics.CodeAnalysis, and are here so we can still compile against the older frameworks. -/// - -namespace Calamari.Common -{ - [AttributeUsage(AttributeTargets.Property | AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)] - public sealed class NotNullIfNotNullAttribute : Attribute - { - public NotNullIfNotNullAttribute(string parameterName) - { - this.ParameterName = parameterName; - } - - public string ParameterName { get; } - } - - [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, Inherited = false)] - public sealed class DisallowNullAttribute : Attribute - { - } - - [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, Inherited = false)] - public sealed class MaybeNullAttribute : Attribute - { - } - - [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, Inherited = false)] - public sealed class NotNullAttribute : Attribute - { - } - - /// Specifies that when a method returns , the parameter will not be null even if the corresponding type allows it. - [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] - public sealed class NotNullWhenAttribute : Attribute - { - /// Initializes the attribute with the specified return value condition. - /// - /// The return value condition. If the method returns this value, the associated parameter will not be null. - /// - public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; - - /// Gets the return value condition. - public bool ReturnValue { get; } - } -} -#endif \ No newline at end of file diff --git a/source/Calamari.Common/Plumbing/Extensions/EnumerableExtensions.cs b/source/Calamari.Common/Plumbing/Extensions/EnumerableExtensions.cs deleted file mode 100644 index 0a6b184be1..0000000000 --- a/source/Calamari.Common/Plumbing/Extensions/EnumerableExtensions.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Calamari.Common.Plumbing.Extensions -{ - public static class EnumerableExtensions - { - internal static IEnumerable DistinctBy(this IEnumerable source, - Func keySelector) - { - var knownKeys = new HashSet(); - foreach (var element in source) - if (knownKeys.Add(keySelector(element))) - yield return element; - } - } -} \ No newline at end of file diff --git a/source/Calamari.Common/Plumbing/Extensions/ScriptingEnvironment.cs b/source/Calamari.Common/Plumbing/Extensions/ScriptingEnvironment.cs index c4a8a3f08f..de17250510 100644 --- a/source/Calamari.Common/Plumbing/Extensions/ScriptingEnvironment.cs +++ b/source/Calamari.Common/Plumbing/Extensions/ScriptingEnvironment.cs @@ -9,15 +9,6 @@ namespace Calamari.Common.Plumbing.Extensions { public class ScriptingEnvironment { - public static bool IsNetFramework() - { -#if NETFRAMEWORK - return true; -#else - return false; -#endif - } - public static bool IsNet45OrNewer() { // Class "ReflectionContext" exists from .NET 4.5 onwards. diff --git a/source/Calamari.Common/Plumbing/Extensions/VersionExtensions.cs b/source/Calamari.Common/Plumbing/Extensions/VersionExtensions.cs index 01a593ee72..b76bef1d94 100644 --- a/source/Calamari.Common/Plumbing/Extensions/VersionExtensions.cs +++ b/source/Calamari.Common/Plumbing/Extensions/VersionExtensions.cs @@ -1,5 +1,4 @@ -#if USE_NUGET_V3_LIBS -using System; +using System; using NuGet.Versioning; using Octopus.Versioning; @@ -23,5 +22,4 @@ public static NuGetVersion ToNuGetVersion(this IVersion version) version.Metadata); } } -} -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/source/Calamari.Common/Plumbing/FileSystem/CalamariPhysicalFileSystem.cs b/source/Calamari.Common/Plumbing/FileSystem/CalamariPhysicalFileSystem.cs index 579d4f49b1..e0aa131489 100644 --- a/source/Calamari.Common/Plumbing/FileSystem/CalamariPhysicalFileSystem.cs +++ b/source/Calamari.Common/Plumbing/FileSystem/CalamariPhysicalFileSystem.cs @@ -24,9 +24,7 @@ public abstract class CalamariPhysicalFileSystem : ICalamariFileSystem static CalamariPhysicalFileSystem() { -#if NETSTANDARD Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); // Required to use code pages in .NET Standard -#endif DefaultInputEncodingPrecedence = new List { new UTF8Encoding(false, true), diff --git a/source/Calamari.Common/Plumbing/FileSystem/FileOperations.cs b/source/Calamari.Common/Plumbing/FileSystem/FileOperations.cs index 9aa76bd92f..0e6d09c2f7 100644 --- a/source/Calamari.Common/Plumbing/FileSystem/FileOperations.cs +++ b/source/Calamari.Common/Plumbing/FileSystem/FileOperations.cs @@ -156,125 +156,4 @@ public string GetCurrentDirectory() return Directory.GetCurrentDirectory(); } } - -#if USE_ALPHAFS_FOR_LONG_FILE_PATH_SUPPORT - public class LongPathsFile : IFile - { - public void Delete(string path) - { - Alphaleonis.Win32.Filesystem.File.Delete(path); - } - - public bool Exists(string? path) - { - return Alphaleonis.Win32.Filesystem.File.Exists(path); - } - - public byte[] ReadAllBytes(string path) - { - return Alphaleonis.Win32.Filesystem.File.ReadAllBytes(path); - } - - public void WriteAllBytes(string path, byte[] bytes) - { - Alphaleonis.Win32.Filesystem.File.WriteAllBytes(path, bytes); - } - - public void Move(string source, string destination) - { - Alphaleonis.Win32.Filesystem.File.Move(source, destination); - } - - public void SetAttributes(string path, FileAttributes fileAttributes) - { - Alphaleonis.Win32.Filesystem.File.SetAttributes(path, fileAttributes); - } - - public DateTime GetCreationTime(string path) - { - return Alphaleonis.Win32.Filesystem.File.GetCreationTime(path); - } - - public Stream Open(string path, FileMode mode, FileAccess access, FileShare share) - { - return Alphaleonis.Win32.Filesystem.File.Open(path, mode, access, share); - } - - public void Copy(string source, string destination, bool overwrite) - { - Alphaleonis.Win32.Filesystem.File.Copy(source, destination, overwrite); - } - } - - public class LongPathsDirectory : IDirectory - { - public void CreateDirectory(string path) - { - Alphaleonis.Win32.Filesystem.Directory.CreateDirectory(path); - } - - public void Delete(string path, bool recursive) - { - Alphaleonis.Win32.Filesystem.Directory.Delete(path, recursive); - } - - public bool Exists(string? path) - { - return Alphaleonis.Win32.Filesystem.Directory.Exists(path); - } - - public string[] GetFileSystemEntries(string path) - { - return Alphaleonis.Win32.Filesystem.Directory.GetFileSystemEntries(path); - } - - public IEnumerable EnumerateDirectories(string path) - { - return Alphaleonis.Win32.Filesystem.Directory.EnumerateDirectories(path); - } - - public IEnumerable EnumerateDirectoriesRecursively(string path) - { - return Alphaleonis.Win32.Filesystem.Directory.EnumerateDirectories(path, "*", SearchOption.AllDirectories); - } - - public IEnumerable EnumerateFiles(string parentDirectoryPath, params string[] searchPatterns) - { - return EnumerateFiles(parentDirectoryPath, SearchOption.TopDirectoryOnly, searchPatterns); - } - - public IEnumerable EnumerateFilesRecursively(string parentDirectoryPath, params string[] searchPatterns) - { - return EnumerateFiles(parentDirectoryPath, SearchOption.AllDirectories, searchPatterns); - } - - private IEnumerable EnumerateFiles( - string parentDirectoryPath, - SearchOption searchOption, - string[] searchPatterns) - { - // Note we aren't using Alphaleonis.Win32.Filesystem.Directory.EnumerateFiles which handles long file paths due to performance issues. - var parentDirectoryInfo = new DirectoryInfo(parentDirectoryPath); - - return searchPatterns.Length == 0 - ? parentDirectoryInfo.GetFiles("*", searchOption).Select(fi => fi.FullName) - : searchPatterns.SelectMany(pattern => parentDirectoryInfo.GetFiles(pattern, searchOption).Select(fi => fi.FullName)).Distinct(); - } - - public IEnumerable GetFiles(string path, string searchPattern) - { - return Alphaleonis.Win32.Filesystem.Directory.GetFiles(path, searchPattern); - } - - public IEnumerable GetDirectories(string path) - { - return Alphaleonis.Win32.Filesystem.Directory.GetDirectories(path); - } - - public string GetCurrentDirectory() - { - return Alphaleonis.Win32.Filesystem.Directory.GetCurrentDirectory(); - } - } -#endif } \ No newline at end of file diff --git a/source/Calamari.Common/Plumbing/FileSystem/WindowsPhysicalFileSystem.cs b/source/Calamari.Common/Plumbing/FileSystem/WindowsPhysicalFileSystem.cs index cd21d8f2f9..242cd03a5e 100644 --- a/source/Calamari.Common/Plumbing/FileSystem/WindowsPhysicalFileSystem.cs +++ b/source/Calamari.Common/Plumbing/FileSystem/WindowsPhysicalFileSystem.cs @@ -5,14 +5,6 @@ namespace Calamari.Common.Plumbing.FileSystem { public class WindowsPhysicalFileSystem : CalamariPhysicalFileSystem { - public WindowsPhysicalFileSystem() - { -#if USE_ALPHAFS_FOR_LONG_FILE_PATH_SUPPORT - File = new LongPathsFile(); - Directory = new LongPathsDirectory(); -#endif - } - [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] [return: MarshalAs(UnmanagedType.Bool)] static extern bool GetDiskFreeSpaceEx(string lpDirectoryName, out ulong lpFreeBytesAvailable, out ulong lpTotalNumberOfBytes, out ulong lpTotalNumberOfFreeBytes); diff --git a/source/Calamari.Common/Plumbing/SecurityProtocols.cs b/source/Calamari.Common/Plumbing/SecurityProtocols.cs index 19a07d5d54..7592acf454 100644 --- a/source/Calamari.Common/Plumbing/SecurityProtocols.cs +++ b/source/Calamari.Common/Plumbing/SecurityProtocols.cs @@ -14,23 +14,19 @@ public static void EnableAllSecurityProtocols() // TLS1.1 and below was discontinued on MavenCentral as of 18 June 2018 //https://central.sonatype.org/articles/2018/May/04/discontinue-support-for-tlsv11-and-below/ - var securityProcotolTypes = -#if HAS_SSL3 - SecurityProtocolType.Ssl3 | -#endif - SecurityProtocolType.Tls; + var securityProtocolTypes = SecurityProtocolType.Tls; // Enum.IsDefined is used as even though it may be compiled against net40 which does not have the flag // if at runtime it runs on say net475 the flags are present if (Enum.IsDefined(typeof(SecurityProtocolType), 768)) - securityProcotolTypes = securityProcotolTypes | (SecurityProtocolType)768; + securityProtocolTypes |= (SecurityProtocolType)768; if (Enum.IsDefined(typeof(SecurityProtocolType), 3072)) - securityProcotolTypes = securityProcotolTypes | (SecurityProtocolType)3072; + securityProtocolTypes |= (SecurityProtocolType)3072; else Log.Verbose($"TLS1.2 is not supported, this means that some outgoing connections to third party endpoints will not work as they now only support TLS1.2.{Environment.NewLine}This includes GitHub feeds and Maven feeds."); - ServicePointManager.SecurityProtocol = securityProcotolTypes; + ServicePointManager.SecurityProtocol = securityProtocolTypes; } } } \ No newline at end of file From 0831b612a2f243af58e2efd2c5ba6d4437a5c7e4 Mon Sep 17 00:00:00 2001 From: Alastair Pitts Date: Thu, 27 Nov 2025 17:35:04 +1100 Subject: [PATCH 11/22] Change remaining projects to .NET 8 from netstandard --- source/Calamari.Aws/Calamari.Aws.csproj | 2 +- .../Deployment/AmazonFileUploadException.cs | 1 - .../Calamari.CloudAccounts.csproj | 2 +- .../Calamari.GoogleCloudAccounts.csproj | 2 +- source/Calamari.Shared/Calamari.Shared.csproj | 5 +- .../Commands/ApplyDeltaCommand.cs | 4 - .../CryptoKeySecurityAccessRules.cs | 3 +- .../Download/FeedCredentialsProvider.cs | 95 ------ .../Download/FixedFilePathResolver.cs | 63 ---- .../Download/NuGetPackageDownloader.cs | 10 +- .../NuGet/InternalNuGetPackageDownloader.cs | 50 --- .../Packages/NuGet/NuGetV2Downloader.cs | 68 ---- .../Packages/NuGet/NuGetV3Downloader.cs | 322 ------------------ .../Packages/NuGet/NuGetV3LibDownloader.cs | 8 +- .../Calamari.Shared/Util/GoDurationParser.cs | 7 +- .../Acme.JsonFileOutput.csproj | 2 +- .../Packages/Acme.Package/Acme.Package.csproj | 2 +- .../Acme.PackageBilingual.csproj | 2 +- .../Packages/Acme.Service/Acme.Service.csproj | 2 +- .../Acme.StructuredConfigFiles.csproj | 2 +- .../Acme.Web.Tests/Acme.Web.Tests.csproj | 2 +- .../Packages/Acme.Web/Acme.Web.Nix.csproj | 2 +- .../Packages/Acme.Web/Acme.Web.csproj | 2 +- .../Octopus.Sample.AzureCloudService.csproj | 2 +- ...oxyEnvironmentVariablesGeneratorFixture.cs | 1 - .../Proxies/WebProxyInitializerFixture.cs | 1 - 26 files changed, 19 insertions(+), 643 deletions(-) delete mode 100644 source/Calamari.Shared/Integration/Packages/Download/FeedCredentialsProvider.cs delete mode 100644 source/Calamari.Shared/Integration/Packages/Download/FixedFilePathResolver.cs delete mode 100644 source/Calamari.Shared/Integration/Packages/NuGet/NuGetV2Downloader.cs delete mode 100644 source/Calamari.Shared/Integration/Packages/NuGet/NuGetV3Downloader.cs diff --git a/source/Calamari.Aws/Calamari.Aws.csproj b/source/Calamari.Aws/Calamari.Aws.csproj index 2b7226dd6d..da7185a30c 100644 --- a/source/Calamari.Aws/Calamari.Aws.csproj +++ b/source/Calamari.Aws/Calamari.Aws.csproj @@ -18,7 +18,7 @@ Calamari.Aws.exe.manifest - netstandard2.1 + net8.0 default true diff --git a/source/Calamari.Aws/Deployment/AmazonFileUploadException.cs b/source/Calamari.Aws/Deployment/AmazonFileUploadException.cs index 0ed8fb851d..70134e484d 100644 --- a/source/Calamari.Aws/Deployment/AmazonFileUploadException.cs +++ b/source/Calamari.Aws/Deployment/AmazonFileUploadException.cs @@ -8,6 +8,5 @@ public class AmazonFileUploadException : Exception public AmazonFileUploadException(){} public AmazonFileUploadException(string message) : base(message){} public AmazonFileUploadException(string message, Exception innerException) : base(message, innerException){} - protected AmazonFileUploadException(SerializationInfo info, StreamingContext context) : base(info, context){} } } \ No newline at end of file diff --git a/source/Calamari.CloudAccounts/Calamari.CloudAccounts.csproj b/source/Calamari.CloudAccounts/Calamari.CloudAccounts.csproj index ddcbae89ef..2b0eabda77 100644 --- a/source/Calamari.CloudAccounts/Calamari.CloudAccounts.csproj +++ b/source/Calamari.CloudAccounts/Calamari.CloudAccounts.csproj @@ -2,7 +2,7 @@ Calamari.CloudAccounts - netstandard2.1 + net8.0 default Octopus.Calamari.CloudAccounts Calamari.CloudAccounts diff --git a/source/Calamari.GoogleCloudAccounts/Calamari.GoogleCloudAccounts.csproj b/source/Calamari.GoogleCloudAccounts/Calamari.GoogleCloudAccounts.csproj index 0314511fa2..518f285456 100644 --- a/source/Calamari.GoogleCloudAccounts/Calamari.GoogleCloudAccounts.csproj +++ b/source/Calamari.GoogleCloudAccounts/Calamari.GoogleCloudAccounts.csproj @@ -2,7 +2,7 @@ Calamari.GoogleCloudAccounts - netstandard2.1 + net8.0 default CS8632 diff --git a/source/Calamari.Shared/Calamari.Shared.csproj b/source/Calamari.Shared/Calamari.Shared.csproj index 85226da4c0..111c189d01 100644 --- a/source/Calamari.Shared/Calamari.Shared.csproj +++ b/source/Calamari.Shared/Calamari.Shared.csproj @@ -23,10 +23,7 @@ Calamari default enable - netstandard2.1 - - - $(DefineConstants);USE_NUGET_V3_LIBS + net8.0 diff --git a/source/Calamari.Shared/Commands/ApplyDeltaCommand.cs b/source/Calamari.Shared/Commands/ApplyDeltaCommand.cs index 5986e7767c..8ebdbd357a 100644 --- a/source/Calamari.Shared/Commands/ApplyDeltaCommand.cs +++ b/source/Calamari.Shared/Commands/ApplyDeltaCommand.cs @@ -54,11 +54,7 @@ public override int Execute(string[] commandLineArguments) ValidateParameters(out basisFilePath, out deltaFilePath, out newFilePath); var tempNewFilePath = newFilePath + ".partial"; -#if USE_OCTODIFF_EXE - var factory = new OctoDiffCommandLineRunner(commandLineRunner); -#else var factory = new OctoDiffLibraryCallRunner(); -#endif var octoDiff = factory.OctoDiff .Action("patch") .PositionalArgument(basisFilePath) diff --git a/source/Calamari.Shared/Integration/Certificates/CryptoKeySecurityAccessRules.cs b/source/Calamari.Shared/Integration/Certificates/CryptoKeySecurityAccessRules.cs index 29ce0b6036..d8a55f1642 100644 --- a/source/Calamari.Shared/Integration/Certificates/CryptoKeySecurityAccessRules.cs +++ b/source/Calamari.Shared/Integration/Certificates/CryptoKeySecurityAccessRules.cs @@ -14,7 +14,6 @@ namespace Calamari.Integration.Certificates { - #if !NETFX [Flags] public enum CryptoKeyRights { @@ -254,7 +253,7 @@ internal static CryptoKeyRights RightsFromAccessMask(int accessMask) return (CryptoKeyRights) accessMask; } } -#endif + public static class CryptoKeySecurityAccessRules { diff --git a/source/Calamari.Shared/Integration/Packages/Download/FeedCredentialsProvider.cs b/source/Calamari.Shared/Integration/Packages/Download/FeedCredentialsProvider.cs deleted file mode 100644 index f8e5dba04e..0000000000 --- a/source/Calamari.Shared/Integration/Packages/Download/FeedCredentialsProvider.cs +++ /dev/null @@ -1,95 +0,0 @@ -#if USE_NUGET_V2_LIBS -using System; -using System.Collections.Concurrent; -using System.Net; -using NuGet; - -namespace Calamari.Integration.Packages.Download -{ - public class FeedCredentialsProvider : ICredentialProvider - { - FeedCredentialsProvider() - { - } - - public static FeedCredentialsProvider Instance = new FeedCredentialsProvider(); - static readonly ConcurrentDictionary Credentials = new ConcurrentDictionary(); - static readonly ConcurrentDictionary Retries = new ConcurrentDictionary(); - - public void SetCredentials(Uri uri, ICredentials credential) - { - Credentials[Canonicalize(uri)] = credential; - } - - public ICredentials GetCredentials(Uri uri, IWebProxy proxy, CredentialType credentialType, bool retrying) - { - var url = Canonicalize(uri); - var retry = Retries.GetOrAdd(url, _ => new RetryTracker()); - - if (!retrying) - { - retry.Reset(); - } - else - { - var retryAllowed = retry.AttemptRetry(); - if (!retryAllowed) - return null; - } - - return new DynamicCachedCredential(url); - } - - ICredentials GetCurrentCredentials(string url) - { - ICredentials credential; - if (!Credentials.TryGetValue(url, out credential)) - { - credential = CredentialCache.DefaultNetworkCredentials; - } - - return credential; - } - - string Canonicalize(Uri uri) - { - return uri.Authority.ToLowerInvariant().Trim(); - } - - public class RetryTracker - { - const int MaxAttempts = 3; - int currentCount; - - public bool AttemptRetry() - { - if (currentCount > MaxAttempts) return false; - - currentCount++; - return true; - } - - public void Reset() - { - currentCount = 0; - } - } - - class DynamicCachedCredential : CredentialCache, ICredentials - { - readonly string url; - - public DynamicCachedCredential(string url) - { - this.url = url; - } - - NetworkCredential ICredentials.GetCredential(Uri uri, string authType) - { - var credential = Instance.GetCurrentCredentials(url); - return credential.GetCredential(uri, authType); - } - } - } -} -#endif \ No newline at end of file diff --git a/source/Calamari.Shared/Integration/Packages/Download/FixedFilePathResolver.cs b/source/Calamari.Shared/Integration/Packages/Download/FixedFilePathResolver.cs deleted file mode 100644 index 7ad8fbf500..0000000000 --- a/source/Calamari.Shared/Integration/Packages/Download/FixedFilePathResolver.cs +++ /dev/null @@ -1,63 +0,0 @@ -#if USE_NUGET_V2_LIBS -using System; -using System.IO; -using NuGet; - -namespace Calamari.Integration.Packages.Download -{ - public class FixedFilePathResolver : IPackagePathResolver - { - readonly string packageName; - readonly string filePathNameToReturn; - - public FixedFilePathResolver(string packageName, string filePathNameToReturn) - { - if (packageName == null) - throw new ArgumentNullException("packageName"); - if (filePathNameToReturn == null) - throw new ArgumentNullException("filePathNameToReturn"); - - this.packageName = packageName; - this.filePathNameToReturn = filePathNameToReturn; - } - - public string GetInstallPath(IPackage package) - { - EnsureRightPackage(package.Id); - return Path.GetDirectoryName(filePathNameToReturn); - } - - public string GetPackageDirectory(IPackage package) - { - return GetPackageDirectory(package.Id, package.Version); - } - - public string GetPackageFileName(IPackage package) - { - return GetPackageFileName(package.Id, package.Version); - } - - public string GetPackageDirectory(string packageId, SemanticVersion version) - { - EnsureRightPackage(packageId); - return string.Empty; - } - - public string GetPackageFileName(string packageId, SemanticVersion version) - { - EnsureRightPackage(packageId); - return Path.GetFileName(filePathNameToReturn); - } - - void EnsureRightPackage(string packageId) - { - var samePackage = string.Equals(packageId, packageName, StringComparison.OrdinalIgnoreCase); - - if (!samePackage) - { - throw new ArgumentException(string.Format("Expected to be asked for the path for package {0}, but was instead asked for the path for package {1}", packageName, packageId)); - } - } - } -} -#endif \ No newline at end of file diff --git a/source/Calamari.Shared/Integration/Packages/Download/NuGetPackageDownloader.cs b/source/Calamari.Shared/Integration/Packages/Download/NuGetPackageDownloader.cs index 6abc0b65e1..c281efb2f0 100644 --- a/source/Calamari.Shared/Integration/Packages/Download/NuGetPackageDownloader.cs +++ b/source/Calamari.Shared/Integration/Packages/Download/NuGetPackageDownloader.cs @@ -11,11 +11,8 @@ using Calamari.Integration.Packages.NuGet; using Octopus.Versioning; using PackageName = Calamari.Common.Features.Packages.PackageName; -#if USE_NUGET_V2_LIBS -using NuGet; -#else using NuGet.Packaging; -#endif + namespace Calamari.Integration.Packages.Download { @@ -124,11 +121,8 @@ PackagePhysicalFileMetadata DownloadPackage( void CheckWhetherThePackageHasDependencies(PackagePhysicalFileMetadata pkg) { var nuGetMetadata = new LocalNuGetPackage(pkg.FullFilePath).Metadata; -#if USE_NUGET_V3_LIBS var dependencies = nuGetMetadata.DependencyGroups.SelectMany(ds => ds.Packages).ToArray(); -#else - var dependencies = nuGetMetadata.DependencySets.SelectMany(ds => ds.Dependencies).ToArray(); -#endif + if (dependencies.Any()) Log.Info( "NuGet packages with dependencies are not currently supported, and dependencies won't be installed on the Tentacle. The package '{0} {1}' appears to have the following dependencies: {2}. For more information please see {3}", diff --git a/source/Calamari.Shared/Integration/Packages/NuGet/InternalNuGetPackageDownloader.cs b/source/Calamari.Shared/Integration/Packages/NuGet/InternalNuGetPackageDownloader.cs index a3c03fb476..6618f3097a 100644 --- a/source/Calamari.Shared/Integration/Packages/NuGet/InternalNuGetPackageDownloader.cs +++ b/source/Calamari.Shared/Integration/Packages/NuGet/InternalNuGetPackageDownloader.cs @@ -98,60 +98,10 @@ private void DownloadPackageAction(string packageId, IVersion version, Uri feedU return; } -#if USE_NUGET_V2_LIBS - var timeout = GetHttpTimeout(); - if (IsHttp(feedUri.ToString())) - { - if (NuGetV3Downloader.CanHandle(feedUri, feedCredentials, timeout)) - { - NuGetV3Downloader.DownloadPackage(packageId, version, feedUri, feedCredentials, targetFilePath, timeout); - } - else - { - WarnIfHttpTimeoutHasBeenSet(); - NuGetV2Downloader.DownloadPackage(packageId, version.ToString(), feedUri, feedCredentials, targetFilePath); - } - } -#else - else - { WarnIfHttpTimeoutHasBeenSet(); NuGetV3LibDownloader.DownloadPackage(packageId, version, feedUri, feedCredentials, targetFilePath); - } -#endif - } - -#if USE_NUGET_V2_LIBS - TimeSpan GetHttpTimeout() - { - const string expectedTimespanFormat = "c"; - - // Equal to Timeout.InfiniteTimeSpan, which isn't available in net40 - var defaultTimeout = new TimeSpan(0, 0, 0, 0, -1); - - var rawTimeout = variables.Get(KnownVariables.NugetHttpTimeout); - if (string.IsNullOrWhiteSpace(rawTimeout)) - { - return defaultTimeout; - } - - if (TimeSpan.TryParseExact(rawTimeout, expectedTimespanFormat, null, out var parsedTimeout)) - { - return parsedTimeout; - } - - var exampleTimespan = new TimeSpan(0, 0, 1, 0).ToString(expectedTimespanFormat); - - var message = $"The variable {KnownVariables.NugetHttpTimeout} couldn't be parsed as a timespan. " + - $"Expected a value like '{exampleTimespan}' but received '{rawTimeout}'. " + - $"Defaulting to '{defaultTimeout.ToString(expectedTimespanFormat)}'."; - - Log.Warn(message); - return defaultTimeout; } - -#endif void WarnIfHttpTimeoutHasBeenSet() { diff --git a/source/Calamari.Shared/Integration/Packages/NuGet/NuGetV2Downloader.cs b/source/Calamari.Shared/Integration/Packages/NuGet/NuGetV2Downloader.cs deleted file mode 100644 index e569e7b351..0000000000 --- a/source/Calamari.Shared/Integration/Packages/NuGet/NuGetV2Downloader.cs +++ /dev/null @@ -1,68 +0,0 @@ -#if USE_NUGET_V2_LIBS -using System; -using System.IO; -using System.Net; -using Calamari.Common.Plumbing.Logging; -using Calamari.Integration.Packages.Download; -using NuGet; -using SemanticVersion = NuGet.SemanticVersion; - -namespace Calamari.Integration.Packages.NuGet -{ - public class NuGetV2Downloader - { - public static void DownloadPackage(string packageId, string packageVersion, Uri feedUri, - ICredentials feedCredentials, string targetFilePath) - { - SetFeedCredentials(feedUri, feedCredentials); - - var package = FindPackage(packageId, packageVersion, feedUri, out var downloader); - DownloadPackage(package, targetFilePath, downloader); - } - - private static IPackage FindPackage(string packageId, string packageVersion, Uri feed, out PackageDownloader downloader) - { - var remoteRepository = PackageRepositoryFactory.Default.CreateRepository(feed.AbsoluteUri); - - downloader = remoteRepository is DataServicePackageRepository dspr ? dspr.PackageDownloader : null; - - var requiredVersion = new SemanticVersion(packageVersion); - var package = remoteRepository.FindPackage(packageId, requiredVersion, true, true); - - if (package == null) - throw new Exception($"Could not find package {packageId} {packageVersion} in feed: '{feed}'"); - - if (!requiredVersion.Equals(package.Version)) - { - throw new Exception($"The package version '{package.Version}' returned from the package repository doesn't match the requested package version '{requiredVersion}'."); - } - - return package; - } - - private static void DownloadPackage(IPackage package, string fullPathToDownloadTo, PackageDownloader directDownloader) - { - Log.VerboseFormat("Found package {0} v{1}", package.Id, package.Version); - Log.Verbose("Downloading to: " + fullPathToDownloadTo); - - if (package is DataServicePackage dsp && directDownloader != null) - { - Log.Verbose("A direct download is possible; bypassing the NuGet machine cache"); - using (var targetFile = new FileStream(fullPathToDownloadTo, FileMode.CreateNew)) - directDownloader.DownloadPackage(dsp.DownloadUrl, dsp, targetFile); - return; - } - - var physical = new PhysicalFileSystem(Path.GetDirectoryName(fullPathToDownloadTo)); - var local = new LocalPackageRepository(new FixedFilePathResolver(package.Id, fullPathToDownloadTo), physical); - local.AddPackage(package); - } - - static void SetFeedCredentials(Uri feedUri, ICredentials feedCredentials) - { - FeedCredentialsProvider.Instance.SetCredentials(feedUri, feedCredentials); - HttpClient.DefaultCredentialProvider = FeedCredentialsProvider.Instance; - } - } -} -#endif \ No newline at end of file diff --git a/source/Calamari.Shared/Integration/Packages/NuGet/NuGetV3Downloader.cs b/source/Calamari.Shared/Integration/Packages/NuGet/NuGetV3Downloader.cs deleted file mode 100644 index 28b1e0acc9..0000000000 --- a/source/Calamari.Shared/Integration/Packages/NuGet/NuGetV3Downloader.cs +++ /dev/null @@ -1,322 +0,0 @@ -// Much of this class was based on code from https://github.com/NuGet/NuGet.Client. It was ported, as the NuGet libraries are .NET 4.5 and Calamari is .NET 4.0 -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.// -#if USE_NUGET_V2_LIBS -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Web; -using Calamari.Common.Commands; -using Calamari.Common.Plumbing.Logging; -using Calamari.Deployment; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using Octopus.CoreUtilities.Extensions; -using Octopus.Versioning; -using Octopus.Versioning.Semver; - -namespace Calamari.Integration.Packages.NuGet -{ - internal static class NuGetV3Downloader - { - public static bool CanHandle(Uri feedUri, ICredentials feedCredentials, TimeSpan httpTimeout) - { - if (feedUri.ToString().EndsWith(".json", StringComparison.OrdinalIgnoreCase)) - { - return true; - } - - return IsJsonEndpoint(feedUri, feedCredentials, httpTimeout); - } - - static bool IsJsonEndpoint(Uri feedUri, ICredentials feedCredentials, TimeSpan httpTimeout) - { - var request = new HttpRequestMessage(HttpMethod.Get, feedUri); - - using (var httpClient = CreateHttpClient(feedCredentials, httpTimeout)) - { - var sending = httpClient.SendAsync(request); - sending.Wait(); - - using (var response = sending.Result) - { - response.EnsureSuccessStatusCode(); - - return response.Content.Headers.ContentType.MediaType == "application/json"; - } - } - } - - class PackageIdentifier - { - public PackageIdentifier(string packageId, IVersion version) - { - Id = packageId.ToLowerInvariant(); - Version = version.ToString().ToLowerInvariant(); - SemanticVersion = version; - SemanticVersionWithoutMetadata = new SemanticVersion(version.Major, version.Minor, version.Patch, version.Revision, version.Release, null); - } - - public string Id { get; } - public string Version { get; } - public IVersion SemanticVersion { get; } - public IVersion SemanticVersionWithoutMetadata { get; } - } - - public static void DownloadPackage(string packageId, IVersion version, Uri feedUri, ICredentials feedCredentials, string targetFilePath, TimeSpan httpTimeout) - { - var packageIdentifier = new PackageIdentifier(packageId, version); - - var downloadUri = GetDownloadUri(packageIdentifier, feedUri, feedCredentials, httpTimeout); - if (downloadUri == null) - { - throw new InvalidOperationException($"Unable to find url to download package: {version} with version: {version} from feed: {feedUri}"); - } - - Log.Verbose($"Downloading package from '{downloadUri}'"); - - using (var nupkgFile = new FileStream(targetFilePath, FileMode.Create, FileAccess.ReadWrite, FileShare.None)) - { - GetHttp(downloadUri, feedCredentials, httpTimeout, pkgStream => - { - pkgStream.CopyTo(nupkgFile); - }); - } - } - - static Uri? GetDownloadUri(PackageIdentifier packageIdentifier, Uri feedUri, ICredentials feedCredentials, TimeSpan httpTimeout) - { - var json = GetServiceIndexJson(feedUri, feedCredentials, httpTimeout); - if (json == null) - { - throw new CommandException($"'{feedUri}' is not a valid NuGet v3 feed"); - } - - var resources = GetServiceResources(json); - - var packageBaseDownloadUri = GetPackageBaseDownloadUri(resources, packageIdentifier); - if (packageBaseDownloadUri != null) return packageBaseDownloadUri; - - return GetPackageRegistrationDownloadUri(feedCredentials, httpTimeout, resources, packageIdentifier); - } - - static Uri? GetPackageRegistrationDownloadUri(ICredentials feedCredentials, TimeSpan httpTimeout, IDictionary> resources, PackageIdentifier packageIdentifier) - { - var packageRegistrationUri = GetPackageRegistrationUri(resources, packageIdentifier.Id); - var packageRegistrationResponse = GetJsonResponse(packageRegistrationUri, feedCredentials, httpTimeout); - - // Package Registration Response structure - // https://docs.microsoft.com/en-us/nuget/api/registration-base-url-resource#response - var registrationPages = packageRegistrationResponse["items"]; - - // Registration Page structure - // https://docs.microsoft.com/en-us/nuget/api/registration-base-url-resource#registration-page-object - foreach (var registrationPage in registrationPages) - { - var registrationLeaves = registrationPage["items"]; - if (registrationLeaves == null) - { - // narrow version to specific page. - var versionedRegistrationPage = registrationPages.FirstOrDefault(x => VersionComparer.Default.Compare(new SemanticVersion(x["lower"].ToString()), packageIdentifier.SemanticVersionWithoutMetadata) <= 0 && VersionComparer.Default.Compare(new SemanticVersion(x["upper"].ToString()), packageIdentifier.SemanticVersionWithoutMetadata) >= 0); - - // If we can't find a page for the version we are looking for, return null. - if (versionedRegistrationPage == null) return null; - - var versionedRegistrationPageResponse = GetJsonResponse(new Uri(versionedRegistrationPage["@id"].ToString()), feedCredentials, httpTimeout); - registrationLeaves = versionedRegistrationPageResponse["items"]; - } - - // Leaf Structure - // https://docs.microsoft.com/en-us/nuget/api/registration-base-url-resource#registration-leaf-object-in-a-page - var leaf = registrationLeaves.FirstOrDefault(x => string.Equals(x["catalogEntry"]["version"].ToString(), packageIdentifier.Version, StringComparison.OrdinalIgnoreCase)); - // If we can't find the leaf registration for the version we are looking for, return null. - if (leaf == null) return null; - - var contentUri = leaf["packageContent"].ToString(); - - // Note: We reformat the packageContent Uri here as Artifactory (and possibly others) does not include +metadata suffixes on its packageContent Uri's - var downloadUri = new Uri($"{contentUri.Remove(contentUri.LastIndexOfAny("/".ToCharArray()) + 1)}{packageIdentifier.Version}"); - - return downloadUri; - } - - return null; - } - - static Uri? GetPackageBaseDownloadUri(IDictionary> resources, PackageIdentifier packageIdentifier) - { - var packageBaseUri = GetPackageBaseUri(resources); - - if (packageBaseUri?.AbsoluteUri.TrimEnd('/') != null) - { - return new Uri($"{packageBaseUri}/{packageIdentifier.Id}/{packageIdentifier.Version}/{packageIdentifier.Id}.{packageIdentifier.Version}.nupkg"); - } - - return null; - } - - static Uri GetPackageRegistrationUri(IDictionary> resources, string normalizedId) - { - var registrationUrl = NuGetServiceTypes.RegistrationsBaseUrl - .Where(serviceType => resources.ContainsKey(serviceType)) - .SelectMany(serviceType => resources[serviceType]) - .First() - .OriginalString.TrimEnd('/'); - - var packageRegistrationUri = new Uri($"{registrationUrl}/{normalizedId}/index.json"); - return packageRegistrationUri; - } - - static HttpClient CreateHttpClient(ICredentials credentials, TimeSpan httpTimeout) - { - var handler = new WebRequestHandler - { - Credentials = credentials, - AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate - }; - - var httpClient = new HttpClient(handler) - { - Timeout = httpTimeout - }; - - httpClient.DefaultRequestHeaders.Add("user-agent", "NuGet Client V3/3.4.3"); - - return httpClient; - } - - static void GetHttp(Uri uri, ICredentials credentials, TimeSpan httpTimeout, Action processContent) - { - var request = new HttpRequestMessage(HttpMethod.Get, uri); - - using (var httpClient = CreateHttpClient(credentials, httpTimeout)) - { - var sending = httpClient.SendAsync(request); - sending.Wait(); - using (var response = sending.Result) - { - response.EnsureSuccessStatusCode(); - var readingStream = response.Content.ReadAsStreamAsync(); - readingStream.Wait(); - processContent(readingStream.Result); - } - } - } - - static Uri? GetPackageBaseUri(IDictionary> resources) - { - // If index.json contains a flat container resource use that to directly - // construct package download urls. - if (resources.ContainsKey(NuGetServiceTypes.PackageBaseAddress)) - return resources[NuGetServiceTypes.PackageBaseAddress].FirstOrDefault(); - return null; - } - - static JObject? GetServiceIndexJson(Uri feedUri, ICredentials feedCredentials, TimeSpan httpTimeout) - { - var json = GetJsonResponse(feedUri, feedCredentials, httpTimeout); - - if (!IsValidV3Json(json)) return null; - - return json; - } - - static JObject GetJsonResponse(Uri feedUri, ICredentials feedCredentials, TimeSpan httpTimeout) - { - // Parse JSON for package base URL - JObject json = null; - GetHttp(feedUri, - feedCredentials, - httpTimeout, - stream => - { - using (var streamReader = new StreamReader(stream)) - using (var jsonReader = new JsonTextReader(streamReader)) - { - json = JObject.Load(jsonReader); - } - }); - return json; - } - - static bool IsValidV3Json(JObject json) - { - // Use SemVer instead of NuGetVersion, the service index should always be - // in strict SemVer format - JToken versionToken; - if (json.TryGetValue("version", out versionToken) && - versionToken.Type == JTokenType.String) - { - var version = VersionFactory.TryCreateSemanticVersion((string)versionToken); - if (version != null && version.Major == 3) - { - return true; - } - } - return false; - } - - static IDictionary> GetServiceResources(JObject index) - { - var result = new Dictionary>(); - - JToken resources; - if (index.TryGetValue("resources", out resources)) - { - foreach (var resource in resources) - { - JToken type = resource["@type"]; - JToken id = resource["@id"]; - - if (type == null || id == null) - { - continue; - } - - if (type.Type == JTokenType.Array) - { - foreach (var nType in type) - { - AddEndpoint(result, nType, id); - } - } - else - { - AddEndpoint(result, type, id); - } - } - } - - return result; - } - - static void AddEndpoint(IDictionary> result, JToken typeToken, JToken idToken) - { - string type = (string)typeToken; - string id = (string)idToken; - - if (type == null || id == null) - { - return; - } - - List ids; - if (!result.TryGetValue(type, out ids)) - { - ids = new List(); - result.Add(type, ids); - } - - Uri uri; - if (Uri.TryCreate(id, UriKind.Absolute, out uri)) - { - ids.Add(new Uri(id)); - } - } - } -} -#endif \ No newline at end of file diff --git a/source/Calamari.Shared/Integration/Packages/NuGet/NuGetV3LibDownloader.cs b/source/Calamari.Shared/Integration/Packages/NuGet/NuGetV3LibDownloader.cs index eed44db148..a18e0fc838 100644 --- a/source/Calamari.Shared/Integration/Packages/NuGet/NuGetV3LibDownloader.cs +++ b/source/Calamari.Shared/Integration/Packages/NuGet/NuGetV3LibDownloader.cs @@ -1,6 +1,4 @@ -#if USE_NUGET_V3_LIBS - -using System; +using System; using System.Net; using System.Threading; using NuGet.Configuration; @@ -107,6 +105,4 @@ public Task LogAsync(ILogMessage message) } } -} - -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/source/Calamari.Shared/Util/GoDurationParser.cs b/source/Calamari.Shared/Util/GoDurationParser.cs index 87a212671c..487cd0cc71 100644 --- a/source/Calamari.Shared/Util/GoDurationParser.cs +++ b/source/Calamari.Shared/Util/GoDurationParser.cs @@ -47,7 +47,6 @@ static TimeSpan ParseDuration(string duration, bool hasBeenValidated) var matches = DurationRegex.Matches(duration); var result = matches - .Cast() .Select(m => { var value = m.Groups[1].Value; @@ -58,12 +57,8 @@ static TimeSpan ParseDuration(string duration, bool hasBeenValidated) { return TimeSpan.Zero; } - -#if NETFRAMEWORK - return TimeSpan.FromTicks((long)Math.Floor(result.InitialTimeSpan.Ticks * double.Parse(value))); -#else + return result.InitialTimeSpan * double.Parse(value); -#endif }) .Aggregate((accumulator, timeSpan) => accumulator + timeSpan); diff --git a/source/Calamari.Tests/Fixtures/Deployment/Packages/Acme.JsonFileOutput/Acme.JsonFileOutput.csproj b/source/Calamari.Tests/Fixtures/Deployment/Packages/Acme.JsonFileOutput/Acme.JsonFileOutput.csproj index 77036296cf..a672254824 100644 --- a/source/Calamari.Tests/Fixtures/Deployment/Packages/Acme.JsonFileOutput/Acme.JsonFileOutput.csproj +++ b/source/Calamari.Tests/Fixtures/Deployment/Packages/Acme.JsonFileOutput/Acme.JsonFileOutput.csproj @@ -5,7 +5,7 @@ en-US 1.0.0.0 ACME Corporation - netstandard1.0 + net8.0 Acme.JsonFileOutput Acme.JsonFileOutput https://github.com/OctopusDeploy/Calamari/ diff --git a/source/Calamari.Tests/Fixtures/Deployment/Packages/Acme.Package/Acme.Package.csproj b/source/Calamari.Tests/Fixtures/Deployment/Packages/Acme.Package/Acme.Package.csproj index 6801cb609d..aa15b8bac5 100644 --- a/source/Calamari.Tests/Fixtures/Deployment/Packages/Acme.Package/Acme.Package.csproj +++ b/source/Calamari.Tests/Fixtures/Deployment/Packages/Acme.Package/Acme.Package.csproj @@ -5,7 +5,7 @@ en-US 1.0.0.0 ACME Corporation - netstandard1.0 + net8.0 Acme.Package Acme.Package https://github.com/OctopusDeploy/Calamari/ diff --git a/source/Calamari.Tests/Fixtures/Deployment/Packages/Acme.PackageBilingual/Acme.PackageBilingual.csproj b/source/Calamari.Tests/Fixtures/Deployment/Packages/Acme.PackageBilingual/Acme.PackageBilingual.csproj index bba21a1485..6da45eedff 100644 --- a/source/Calamari.Tests/Fixtures/Deployment/Packages/Acme.PackageBilingual/Acme.PackageBilingual.csproj +++ b/source/Calamari.Tests/Fixtures/Deployment/Packages/Acme.PackageBilingual/Acme.PackageBilingual.csproj @@ -5,7 +5,7 @@ en-US 1.0.0.0 ACME Corporation - netstandard1.0 + net8.0 Acme.PackageBilingual Acme.PackageBilingual https://github.com/OctopusDeploy/Calamari/ diff --git a/source/Calamari.Tests/Fixtures/Deployment/Packages/Acme.Service/Acme.Service.csproj b/source/Calamari.Tests/Fixtures/Deployment/Packages/Acme.Service/Acme.Service.csproj index aebc1c8ee4..dd5e74eadb 100644 --- a/source/Calamari.Tests/Fixtures/Deployment/Packages/Acme.Service/Acme.Service.csproj +++ b/source/Calamari.Tests/Fixtures/Deployment/Packages/Acme.Service/Acme.Service.csproj @@ -4,7 +4,7 @@ A sample project containing a Windows service. en-US ACME Corporation - netstandard1.0 + net8.0 Acme.Service Acme.Service https://github.com/OctopusDeploy/Calamari/ diff --git a/source/Calamari.Tests/Fixtures/Deployment/Packages/Acme.StructuredConfigFiles/Acme.StructuredConfigFiles.csproj b/source/Calamari.Tests/Fixtures/Deployment/Packages/Acme.StructuredConfigFiles/Acme.StructuredConfigFiles.csproj index fbb423d80f..782c942328 100644 --- a/source/Calamari.Tests/Fixtures/Deployment/Packages/Acme.StructuredConfigFiles/Acme.StructuredConfigFiles.csproj +++ b/source/Calamari.Tests/Fixtures/Deployment/Packages/Acme.StructuredConfigFiles/Acme.StructuredConfigFiles.csproj @@ -5,7 +5,7 @@ en-US 1.0.0.0 ACME Corporation - netstandard1.0 + net8.0 Acme.StructuredConfigFiles Acme.StructuredConfigFiles https://github.com/OctopusDeploy/Calamari/ diff --git a/source/Calamari.Tests/Fixtures/Deployment/Packages/Acme.Web.Tests/Acme.Web.Tests.csproj b/source/Calamari.Tests/Fixtures/Deployment/Packages/Acme.Web.Tests/Acme.Web.Tests.csproj index df6c53f237..ab1d375751 100644 --- a/source/Calamari.Tests/Fixtures/Deployment/Packages/Acme.Web.Tests/Acme.Web.Tests.csproj +++ b/source/Calamari.Tests/Fixtures/Deployment/Packages/Acme.Web.Tests/Acme.Web.Tests.csproj @@ -4,7 +4,7 @@ Test project for Calamari. en-US Octopus Deploy - netstandard1.0 + net8.0 Acme.Web.Tests Acme.Web.Tests https://github.com/OctopusDeploy/Calamari/ diff --git a/source/Calamari.Tests/Fixtures/Deployment/Packages/Acme.Web/Acme.Web.Nix.csproj b/source/Calamari.Tests/Fixtures/Deployment/Packages/Acme.Web/Acme.Web.Nix.csproj index 36fc3d1102..ac21a9a30a 100644 --- a/source/Calamari.Tests/Fixtures/Deployment/Packages/Acme.Web/Acme.Web.Nix.csproj +++ b/source/Calamari.Tests/Fixtures/Deployment/Packages/Acme.Web/Acme.Web.Nix.csproj @@ -4,7 +4,7 @@ Test project for Calamari. en-US Octopus Deploy - netstandard1.0 + net8.0 Acme.Web Acme.Web https://github.com/OctopusDeploy/Calamari/ diff --git a/source/Calamari.Tests/Fixtures/Deployment/Packages/Acme.Web/Acme.Web.csproj b/source/Calamari.Tests/Fixtures/Deployment/Packages/Acme.Web/Acme.Web.csproj index c90f4bb999..7d4370ee8b 100644 --- a/source/Calamari.Tests/Fixtures/Deployment/Packages/Acme.Web/Acme.Web.csproj +++ b/source/Calamari.Tests/Fixtures/Deployment/Packages/Acme.Web/Acme.Web.csproj @@ -4,7 +4,7 @@ Test project for Calamari. en-US Octopus Deploy - netstandard1.0 + net8.0 Acme.Web Acme.Web https://github.com/OctopusDeploy/Calamari/ diff --git a/source/Calamari.Tests/Fixtures/Deployment/Packages/Octopus.Sample.AzureCloudService/Octopus.Sample.AzureCloudService.csproj b/source/Calamari.Tests/Fixtures/Deployment/Packages/Octopus.Sample.AzureCloudService/Octopus.Sample.AzureCloudService.csproj index 72d5849714..b8413caa65 100644 --- a/source/Calamari.Tests/Fixtures/Deployment/Packages/Octopus.Sample.AzureCloudService/Octopus.Sample.AzureCloudService.csproj +++ b/source/Calamari.Tests/Fixtures/Deployment/Packages/Octopus.Sample.AzureCloudService/Octopus.Sample.AzureCloudService.csproj @@ -5,7 +5,7 @@ en-US 1.0.0.0 Octopus Deploy - netstandard1.0 + net8.0 Octopus.Sample.AzureCloudService Octopus.Sample.AzureCloudService https://github.com/OctopusDeploy/Calamari/ diff --git a/source/Calamari.Tests/Fixtures/Integration/Proxies/ProxyEnvironmentVariablesGeneratorFixture.cs b/source/Calamari.Tests/Fixtures/Integration/Proxies/ProxyEnvironmentVariablesGeneratorFixture.cs index 4b4176ceed..06c0cc6404 100644 --- a/source/Calamari.Tests/Fixtures/Integration/Proxies/ProxyEnvironmentVariablesGeneratorFixture.cs +++ b/source/Calamari.Tests/Fixtures/Integration/Proxies/ProxyEnvironmentVariablesGeneratorFixture.cs @@ -4,7 +4,6 @@ using Calamari.Common.Plumbing; using Calamari.Common.Plumbing.Proxies; using Calamari.Testing.Helpers; -using Calamari.Testing.Requirements; using FluentAssertions; using NUnit.Framework; diff --git a/source/Calamari.Tests/Fixtures/Integration/Proxies/WebProxyInitializerFixture.cs b/source/Calamari.Tests/Fixtures/Integration/Proxies/WebProxyInitializerFixture.cs index 9b2563d65b..072c563ae6 100644 --- a/source/Calamari.Tests/Fixtures/Integration/Proxies/WebProxyInitializerFixture.cs +++ b/source/Calamari.Tests/Fixtures/Integration/Proxies/WebProxyInitializerFixture.cs @@ -3,7 +3,6 @@ using Calamari.Common.Plumbing; using Calamari.Common.Plumbing.Proxies; using Calamari.Testing.Helpers; -using Calamari.Testing.Requirements; using FluentAssertions; using NUnit.Framework; From 242747c1aef7f22c30b990677889a7a0e3b68579 Mon Sep 17 00:00:00 2001 From: Alastair Pitts Date: Thu, 27 Nov 2025 17:36:26 +1100 Subject: [PATCH 12/22] Remove test attribute --- .../RequiresDotNetFrameworkAttribute.cs | 19 ------------------ ...oxyEnvironmentVariablesGeneratorFixture.cs | 2 +- .../Proxies/WebProxyInitializerFixture.cs | 20 +++++++++---------- 3 files changed, 11 insertions(+), 30 deletions(-) delete mode 100644 source/Calamari.Testing/Requirements/RequiresDotNetFrameworkAttribute.cs diff --git a/source/Calamari.Testing/Requirements/RequiresDotNetFrameworkAttribute.cs b/source/Calamari.Testing/Requirements/RequiresDotNetFrameworkAttribute.cs deleted file mode 100644 index 9174388fe0..0000000000 --- a/source/Calamari.Testing/Requirements/RequiresDotNetFrameworkAttribute.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Calamari.Common.Plumbing.Extensions; -using NUnit.Framework; -using NUnit.Framework.Interfaces; -using NUnit.Framework.Internal; - -namespace Calamari.Testing.Requirements -{ - public class RequiresDotNetFrameworkAttribute: NUnitAttribute, IApplyToTest - { - public void ApplyToTest(Test test) - { - if (!ScriptingEnvironment.IsNetFramework()) - { - test.RunState = RunState.Skipped; - test.Properties.Set(PropertyNames.SkipReason, "Requires dotnet Framework"); - } - } - } -} \ No newline at end of file diff --git a/source/Calamari.Tests/Fixtures/Integration/Proxies/ProxyEnvironmentVariablesGeneratorFixture.cs b/source/Calamari.Tests/Fixtures/Integration/Proxies/ProxyEnvironmentVariablesGeneratorFixture.cs index 06c0cc6404..55aa9c8959 100644 --- a/source/Calamari.Tests/Fixtures/Integration/Proxies/ProxyEnvironmentVariablesGeneratorFixture.cs +++ b/source/Calamari.Tests/Fixtures/Integration/Proxies/ProxyEnvironmentVariablesGeneratorFixture.cs @@ -12,7 +12,7 @@ namespace Calamari.Tests.Fixtures.Integration.Proxies [TestFixture] // These tests currently only work in .NET Framework due to an issue with the .NET Core and proxy caching // See https://github.com/OctopusDeploy/Calamari/pull/1504 for more information - [RequiresDotNetFramework] + [Ignore("Currently there is an issue with .NET Core and proxy caching")] public class ProxyEnvironmentVariablesGeneratorFixture { const string BadproxyUrl = "http://proxy-initializer-fixture-bad-proxy:1234"; diff --git a/source/Calamari.Tests/Fixtures/Integration/Proxies/WebProxyInitializerFixture.cs b/source/Calamari.Tests/Fixtures/Integration/Proxies/WebProxyInitializerFixture.cs index 072c563ae6..ce31e3e832 100644 --- a/source/Calamari.Tests/Fixtures/Integration/Proxies/WebProxyInitializerFixture.cs +++ b/source/Calamari.Tests/Fixtures/Integration/Proxies/WebProxyInitializerFixture.cs @@ -51,7 +51,7 @@ static void ResetSystemProxy() } [Test] - [RequiresDotNetFramework] + [Ignore("Currently there is an issue with .NET Core and proxy caching")] public void Initialize_HasSystemProxy_NoProxy() { ProxyRoutines.SetProxy(proxyUrl).Should().BeTrue(); @@ -61,7 +61,7 @@ public void Initialize_HasSystemProxy_NoProxy() } [Test] - [RequiresDotNetFramework] + [Ignore("Currently there is an issue with .NET Core and proxy caching")] public void Initialize_HasSystemProxy_UseSystemProxy() { ProxyRoutines.SetProxy(proxyUrl).Should().BeTrue(); @@ -71,7 +71,7 @@ public void Initialize_HasSystemProxy_UseSystemProxy() } [Test] - [RequiresDotNetFramework] + [Ignore("Currently there is an issue with .NET Core and proxy caching")] public void Initialize_HasSystemProxy_UseSystemProxyWithCredentials() { ProxyRoutines.SetProxy(proxyUrl).Should().BeTrue(); @@ -81,7 +81,7 @@ public void Initialize_HasSystemProxy_UseSystemProxyWithCredentials() } [Test] - [RequiresDotNetFramework] + [Ignore("Currently there is an issue with .NET Core and proxy caching")] public void Initialize_HasSystemProxy_CustomProxy() { ProxyRoutines.SetProxy(BadproxyUrl).Should().BeTrue(); @@ -91,7 +91,7 @@ public void Initialize_HasSystemProxy_CustomProxy() } [Test] - [RequiresDotNetFramework] + [Ignore("Currently there is an issue with .NET Core and proxy caching")] public void Initialize_HasSystemProxy_CustomProxyWithCredentials() { ProxyRoutines.SetProxy(BadproxyUrl).Should().BeTrue(); @@ -101,7 +101,7 @@ public void Initialize_HasSystemProxy_CustomProxyWithCredentials() } [Test] - [RequiresDotNetFramework] + [Ignore("Currently there is an issue with .NET Core and proxy caching")] public void Initialize_NoSystemProxy_NoProxy() { RunWith(false, "", 80, "", ""); @@ -110,7 +110,7 @@ public void Initialize_NoSystemProxy_NoProxy() } [Test] - [RequiresDotNetFramework] + [Ignore("Currently there is an issue with .NET Core and proxy caching")] public void Initialize_NoSystemProxy_UseSystemProxy() { RunWith(true, "", 80, "", ""); @@ -119,7 +119,7 @@ public void Initialize_NoSystemProxy_UseSystemProxy() } [Test] - [RequiresDotNetFramework] + [Ignore("Currently there is an issue with .NET Core and proxy caching")] public void Initialize_NoSystemProxy_UseSystemProxyWithCredentials() { RunWith(true, "", 80, ProxyUserName, ProxyPassword); @@ -128,7 +128,7 @@ public void Initialize_NoSystemProxy_UseSystemProxyWithCredentials() } [Test] - [RequiresDotNetFramework] + [Ignore("Currently there is an issue with .NET Core and proxy caching")] public void Initialize_NoSystemProxy_CustomProxy() { RunWith(false, proxyHost, proxyPort, "", ""); @@ -137,7 +137,7 @@ public void Initialize_NoSystemProxy_CustomProxy() } [Test] - [RequiresDotNetFramework] + [Ignore("Currently there is an issue with .NET Core and proxy caching")] public void Initialize_NoSystemProxy_CustomProxyWithCredentials() { RunWith(false, proxyHost, proxyPort, ProxyUserName, ProxyPassword); From 5bf9a9c86a4470651eaadb3237bd8f4c4290a856 Mon Sep 17 00:00:00 2001 From: Alastair Pitts Date: Fri, 28 Nov 2025 10:01:18 +1100 Subject: [PATCH 13/22] Try and fix build issue --- build/Build.cs | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/build/Build.cs b/build/Build.cs index b0066c1f1f..d81e8e1b24 100644 --- a/build/Build.cs +++ b/build/Build.cs @@ -66,6 +66,8 @@ partial class Build : NukeBuild [Parameter($"The name of the current git branch. OctoVersion will use this to calculate the version number. This can be set via the environment variable {CiBranchNameEnvVariable}.", Name = CiBranchNameEnvVariable)] string? BranchName { get; set; } + [Parameter] readonly string? ProjectToBuild; + //this is instantiated in the constructor readonly Lazy OctoVersionInfo; @@ -104,7 +106,6 @@ public Build() static AbsolutePath LocalPackagesDirectory => RootDirectory / ".." / "LocalPackages"; static AbsolutePath ConsolidateCalamariPackagesProject => SourceDirectory / "Calamari.ConsolidateCalamariPackages.Tests" / "Calamari.ConsolidateCalamariPackages.Tests.csproj"; static AbsolutePath ConsolidatedPackageDirectory => ArtifactsDirectory / "consolidated"; - static AbsolutePath LegacyCalamariDirectory => PublishDirectory / "Calamari.Legacy"; Lazy NugetVersion { get; } @@ -147,6 +148,9 @@ public Build() d.DependsOn(Clean) .Executes(() => { + //Do one big, default restore + DotNetRestore(s => s.SetProjectFile(Solution)); + var allRuntimeIds = ListAllRuntimeIdentifiersInSolution(); //we restore for all individual runtimes foreach (var runtimeId in allRuntimeIds) @@ -225,6 +229,7 @@ await Task.Run(() => DotNetBuild(s => .SetFramework(calamariPackageMetadata.Framework) .SetRuntime(calamariPackageMetadata.Architecture) .EnableSelfContained() + .EnableNoRestore() //we _should_ have restored everything earlier .SetVerbosity(projectName == "Calamari.Tests" ? DotNetVerbosity.detailed : DotNetVerbosity.minimal))); } finally @@ -347,20 +352,6 @@ async Task CompressCalamariProject(Project project) outputPath.CompressTo(archivePath); }); - Target CopyToLocalPackages => - d => - d.Requires(() => IsLocalBuild) - .DependsOn(PublishCalamariProjects) - .Executes(() => - { - Directory.CreateDirectory(LocalPackagesDirectory); - foreach (AbsolutePath file in Directory.GetFiles(ArtifactsDirectory, "Octopus.Calamari.*.nupkg")) - { - var target = LocalPackagesDirectory / Path.GetFileName(file); - file.Copy(target, ExistsPolicy.FileOverwrite); - } - }); - Target PackageConsolidatedCalamariZip => d => d.DependsOn(PublishCalamariProjects) @@ -437,6 +428,20 @@ async Task CompressCalamariProject(Project project) .SetOutputDirectory(ArtifactsDirectory)); }); + Target CopyToLocalPackages => + d => + d.Requires(() => IsLocalBuild) + .DependsOn(PublishCalamariProjects) + .Executes(() => + { + Directory.CreateDirectory(LocalPackagesDirectory); + foreach (AbsolutePath file in Directory.GetFiles(ArtifactsDirectory, "Octopus.Calamari.*.nupkg")) + { + var target = LocalPackagesDirectory / Path.GetFileName(file); + file.Copy(target, ExistsPolicy.FileOverwrite); + } + }); + Target UpdateCalamariVersionOnOctopusServer => d => d.OnlyWhenStatic(() => SetOctopusServerVersion) From 36625cc9ed7a280d7507537cc648d5b11c3d3215 Mon Sep 17 00:00:00 2001 From: Alastair Pitts Date: Fri, 28 Nov 2025 10:11:33 +1100 Subject: [PATCH 14/22] Remove unused field --- build/Build.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/build/Build.cs b/build/Build.cs index d81e8e1b24..be7e6f1140 100644 --- a/build/Build.cs +++ b/build/Build.cs @@ -66,8 +66,6 @@ partial class Build : NukeBuild [Parameter($"The name of the current git branch. OctoVersion will use this to calculate the version number. This can be set via the environment variable {CiBranchNameEnvVariable}.", Name = CiBranchNameEnvVariable)] string? BranchName { get; set; } - [Parameter] readonly string? ProjectToBuild; - //this is instantiated in the constructor readonly Lazy OctoVersionInfo; From 71908d19bafc71b7922b92120d5b8de71d9ebb2e Mon Sep 17 00:00:00 2001 From: Alastair Pitts Date: Fri, 28 Nov 2025 11:14:33 +1100 Subject: [PATCH 15/22] Add ability to publish individual project --- build/Build.cs | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/build/Build.cs b/build/Build.cs index be7e6f1140..0741c14491 100644 --- a/build/Build.cs +++ b/build/Build.cs @@ -66,6 +66,8 @@ partial class Build : NukeBuild [Parameter($"The name of the current git branch. OctoVersion will use this to calculate the version number. This can be set via the environment variable {CiBranchNameEnvVariable}.", Name = CiBranchNameEnvVariable)] string? BranchName { get; set; } + [Parameter] readonly string? ProjectToBuild; + //this is instantiated in the constructor readonly Lazy OctoVersionInfo; @@ -134,7 +136,8 @@ public Build() Target Clean => d => - d.Executes(() => + d.DependsOn(CheckForbiddenWords) + .Executes(() => { SourceDirectory.GlobDirectories("**/bin", "**/obj", "**/TestResults").ForEach(d => d.DeleteDirectory()); ArtifactsDirectory.CreateOrCleanDirectory(); @@ -148,7 +151,7 @@ public Build() { //Do one big, default restore DotNetRestore(s => s.SetProjectFile(Solution)); - + var allRuntimeIds = ListAllRuntimeIdentifiersInSolution(); //we restore for all individual runtimes foreach (var runtimeId in allRuntimeIds) @@ -177,6 +180,12 @@ public Build() .Where(project => allProjectNames.Contains(project.Name)) .ToList(); + //if this is not + if (!string.IsNullOrEmpty(ProjectToBuild)) + { + calamariProjects = calamariProjects.Where(p => p.Name == ProjectToBuild || p.Name == $"{ProjectToBuild}.Tests").ToList(); + } + CalamariProjects = calamariProjects; //all packages are cross-platform @@ -226,9 +235,7 @@ await Task.Run(() => DotNetBuild(s => .SetConfiguration(Configuration) .SetFramework(calamariPackageMetadata.Framework) .SetRuntime(calamariPackageMetadata.Architecture) - .EnableSelfContained() - .EnableNoRestore() //we _should_ have restored everything earlier - .SetVerbosity(projectName == "Calamari.Tests" ? DotNetVerbosity.detailed : DotNetVerbosity.minimal))); + .EnableSelfContained())); } finally { @@ -318,6 +325,8 @@ async Task CompressCalamariProject(Project project) Target PublishAzureWebAppNetCoreShim => _ => _.DependsOn(RestoreSolution) + //we only build the net core shim when there is the AzureWebApp project is being built + .OnlyWhenDynamic(() => CalamariProjects.Any(p => p.Name == "Calamari.AzureWebApp")) .Executes(() => { if (!OperatingSystem.IsWindows()) @@ -349,11 +358,11 @@ async Task CompressCalamariProject(Project project) outputPath.CompressTo(archivePath); }); - + + Target PackageConsolidatedCalamariZip => d => - d.DependsOn(PublishCalamariProjects) - .Executes(() => + d.Executes(() => { var artifacts = Directory.GetFiles(ArtifactsDirectory, "*.nupkg") .Where(a => !NuGetPackagesToExcludeFromConsolidation.Any(a.Contains)); @@ -467,13 +476,18 @@ async Task CompressCalamariProject(Project project) Target SetTeamCityVersion => d => d.Executes(() => TeamCity.Instance?.SetBuildNumber(NugetVersion.Value)); Target BuildLocal => d => - d.DependsOn(PackCalamariConsolidatedNugetPackage) + d.DependsOn(PublishCalamariProjects) + .DependsOn(PackCalamariConsolidatedNugetPackage) .DependsOn(UpdateCalamariVersionOnOctopusServer); Target BuildCi => d => d.DependsOn(SetTeamCityVersion) + .DependsOn(PublishCalamariProjects) .DependsOn(PackCalamariConsolidatedNugetPackage); + Target BuildAndPublishProject => d => d.OnlyWhenDynamic(() => !string.IsNullOrEmpty(ProjectToBuild)).DependsOn(PublishCalamariProjects); + + public static int Main() => Execute(x => IsServerBuild ? x.BuildCi : x.BuildLocal); void SignDirectory(string directory) From b374e98d04001ffb89b287b0fc857ec44000f2da Mon Sep 17 00:00:00 2001 From: Alastair Pitts Date: Wed, 10 Dec 2025 16:33:40 +1100 Subject: [PATCH 16/22] Fix bad merge --- .../Calamari.AzureWebApp.csproj | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/source/Calamari.AzureWebApp/Calamari.AzureWebApp.csproj b/source/Calamari.AzureWebApp/Calamari.AzureWebApp.csproj index 96bf09da75..ad90149696 100644 --- a/source/Calamari.AzureWebApp/Calamari.AzureWebApp.csproj +++ b/source/Calamari.AzureWebApp/Calamari.AzureWebApp.csproj @@ -58,8 +58,6 @@ - - @@ -74,11 +72,11 @@ - - - - - - - + + + + + + + From b318e5d0b18161fb300f8e356a5e52739b88b10d Mon Sep 17 00:00:00 2001 From: Alastair Pitts Date: Wed, 10 Dec 2025 16:45:53 +1100 Subject: [PATCH 17/22] Fix bad merge --- source/Calamari.AzureWebApp/Calamari.AzureWebApp.csproj | 2 -- 1 file changed, 2 deletions(-) diff --git a/source/Calamari.AzureWebApp/Calamari.AzureWebApp.csproj b/source/Calamari.AzureWebApp/Calamari.AzureWebApp.csproj index ad90149696..49025d9a42 100644 --- a/source/Calamari.AzureWebApp/Calamari.AzureWebApp.csproj +++ b/source/Calamari.AzureWebApp/Calamari.AzureWebApp.csproj @@ -5,8 +5,6 @@ true false Exe - net462;net8.0 - win-x64;linux-x64;osx-x64;linux-arm;linux-arm64 8.0 net8.0 win-x64 From 56c5353bbee3919a27e034be6f145b10ea74a028 Mon Sep 17 00:00:00 2001 From: Alastair Pitts Date: Fri, 9 Jan 2026 10:29:37 +1100 Subject: [PATCH 18/22] Fix consolidated libraries not packing --- build/Build.cs | 48 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/build/Build.cs b/build/Build.cs index 12e9596433..58b093b217 100644 --- a/build/Build.cs +++ b/build/Build.cs @@ -359,8 +359,7 @@ async Task CompressCalamariProject(Project project) outputPath.CompressTo(archivePath); }); - - + Target PackageConsolidatedCalamariZip => d => d.Executes(() => @@ -425,9 +424,47 @@ async Task CompressCalamariProject(Project project) .Add("NUnit.ShowInternalProperties=true"))); }); - Target PackCalamariConsolidatedNugetPackage => + Target PackConsolidationLibrariesNugetPackages => d => d.DependsOn(CalamariConsolidationVerification) + .Executes(() => + { + // Pack the Consolidation Libraries + const string consolidateCalamariPackagesProjectPrefix = "Calamari.ConsolidateCalamariPackages"; + var consolidationLibraryProjects = Solution.Projects.Where(project => project.Name.StartsWith(consolidateCalamariPackagesProjectPrefix)); + + foreach (var project in consolidationLibraryProjects) + { + Log.Information("Packaging {ProjectName}", project.Name); + + var outputDirectory = PublishDirectory / project.Name; + + //publish the consolidated package libraries + DotNetPublish(s => + s.SetConfiguration(Configuration) + .SetProject(project) + .SetOutput(outputDirectory)); + + File.Copy(RootDirectory / "global.json", outputDirectory / "global.json"); + + //sign the output directory + SignDirectory(outputDirectory); + + //pack the project + DotNetPack(s => s + .SetConfiguration(Configuration) + .SetOutputDirectory(ArtifactsDirectory) + .SetProject(outputDirectory) + .EnableNoBuild() + .EnableNoRestore() + .EnableIncludeSource() + .SetVersion(NugetVersion.Value)); + } + }); + + Target PackCalamariConsolidatedNugetPackage => + d => + d.DependsOn(PackConsolidationLibrariesNugetPackages) .Executes(() => { NuGetPack(s => s.SetTargetPath(BuildDirectory / "Calamari.Consolidated.nuspec") @@ -481,13 +518,13 @@ async Task CompressCalamariProject(Project project) const string runtime = "win-x64"; var nukeBuildOutputDirectory = BuildDirectory / "outputs" / runtime / "nukebuild"; nukeBuildOutputDirectory.CreateOrCleanDirectory(); - + DotNetPublish(p => p .SetProject(RootDirectory / "build" / "_build.csproj") .SetConfiguration(Configuration) .SetRuntime(runtime) .EnableSelfContained()); - + await Ci.ZipFolderAndUploadArtifact(nukeBuildOutputDirectory, ArtifactsDirectory / $"nukebuild.{runtime}.zip"); }); @@ -505,7 +542,6 @@ async Task CompressCalamariProject(Project project) .DependsOn(PublishNukeBuild); Target BuildAndPublishProject => d => d.OnlyWhenDynamic(() => !string.IsNullOrEmpty(ProjectToBuild)).DependsOn(PublishCalamariProjects); - public static int Main() => Execute(x => IsServerBuild ? x.BuildCi : x.BuildLocal); From 629a2137882820f439c22e40d0a4a728bad4c807 Mon Sep 17 00:00:00 2001 From: Alastair Pitts Date: Fri, 9 Jan 2026 10:58:52 +1100 Subject: [PATCH 19/22] Fix consolidation --- build/Build.cs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/build/Build.cs b/build/Build.cs index 58b093b217..4f4cfb6981 100644 --- a/build/Build.cs +++ b/build/Build.cs @@ -437,24 +437,23 @@ async Task CompressCalamariProject(Project project) { Log.Information("Packaging {ProjectName}", project.Name); - var outputDirectory = PublishDirectory / project.Name; + var buildDirectory = SourceDirectory / project.Name / "bin" / Configuration; - //publish the consolidated package libraries - DotNetPublish(s => + //Build the consolidated package libraries + DotNetBuild(s => s.SetConfiguration(Configuration) - .SetProject(project) - .SetOutput(outputDirectory)); + .SetProjectFile(project)); - File.Copy(RootDirectory / "global.json", outputDirectory / "global.json"); + File.Copy(RootDirectory / "global.json", buildDirectory / "global.json"); - //sign the output directory - SignDirectory(outputDirectory); + //sign the built directory + SignDirectory(buildDirectory); //pack the project DotNetPack(s => s .SetConfiguration(Configuration) .SetOutputDirectory(ArtifactsDirectory) - .SetProject(outputDirectory) + .SetProject(project) .EnableNoBuild() .EnableNoRestore() .EnableIncludeSource() From b302c20775ac5d951f4e96551808499c52befda8 Mon Sep 17 00:00:00 2001 From: Alastair Pitts Date: Thu, 8 Jan 2026 16:57:09 +1100 Subject: [PATCH 20/22] Execute AzureResourceGroup tests via xUnit, not Nunit --- ...> AzureResourceGroupActionHandlerTests.cs} | 99 ++-------------- .../Calamari.AzureResourceGroup.Tests.csproj | 9 +- .../CalamariTest.cs | 18 +++ .../DeployAzureBicepTemplateCommandFixture.cs | 108 +++--------------- ...tNameFixture.cs => DeploymentNameTests.cs} | 32 +++--- .../GlobalUsings.cs | 4 + .../Support/AzureResourceGroupFixture.cs | 88 ++++++++++++++ .../TestPlatformsAttribute.cs | 14 +++ 8 files changed, 176 insertions(+), 196 deletions(-) rename source/Calamari.AzureResourceGroup.Tests/{AzureResourceGroupActionHandlerFixture.cs => AzureResourceGroupActionHandlerTests.cs} (63%) create mode 100644 source/Calamari.AzureResourceGroup.Tests/CalamariTest.cs rename source/Calamari.AzureResourceGroup.Tests/{DeploymentNameFixture.cs => DeploymentNameTests.cs} (52%) create mode 100644 source/Calamari.AzureResourceGroup.Tests/GlobalUsings.cs create mode 100644 source/Calamari.AzureResourceGroup.Tests/Support/AzureResourceGroupFixture.cs create mode 100644 source/Calamari.AzureResourceGroup.Tests/TestPlatformsAttribute.cs diff --git a/source/Calamari.AzureResourceGroup.Tests/AzureResourceGroupActionHandlerFixture.cs b/source/Calamari.AzureResourceGroup.Tests/AzureResourceGroupActionHandlerTests.cs similarity index 63% rename from source/Calamari.AzureResourceGroup.Tests/AzureResourceGroupActionHandlerFixture.cs rename to source/Calamari.AzureResourceGroup.Tests/AzureResourceGroupActionHandlerTests.cs index 4400d992cc..5fa1da9e0c 100644 --- a/source/Calamari.AzureResourceGroup.Tests/AzureResourceGroupActionHandlerFixture.cs +++ b/source/Calamari.AzureResourceGroup.Tests/AzureResourceGroupActionHandlerTests.cs @@ -1,13 +1,7 @@ using System; using System.IO; -using System.Threading; using System.Threading.Tasks; -using Azure; -using Azure.Core; -using Azure.ResourceManager; -using Azure.ResourceManager.Resources; -using Calamari.Azure; -using Calamari.CloudAccounts; +using Calamari.AzureResourceGroup.Tests.Support; using Calamari.Common.Features.Deployment; using Calamari.Common.Features.Scripts; using Calamari.Common.Plumbing.Variables; @@ -22,79 +16,10 @@ namespace Calamari.AzureResourceGroup.Tests { - [TestFixture] - class AzureResourceGroupActionHandlerFixture + [Collection(nameof(AzureResourceGroupFixture))] + public class AzureResourceGroupActionHandlerFixture(AzureResourceGroupFixture resourceGroupFixture): CalamariTest { - string clientId; - string clientSecret; - string tenantId; - string subscriptionId; - static readonly CancellationTokenSource CancellationTokenSource = new CancellationTokenSource(); - readonly CancellationToken cancellationToken = CancellationTokenSource.Token; - - ArmClient armClient; - SubscriptionResource subscriptionResource; - ResourceGroupResource resourceGroupResource; - string resourceGroupName; - - [OneTimeSetUp] - public async Task Setup() - { - var resourceManagementEndpointBaseUri = - Environment.GetEnvironmentVariable(AccountVariables.ResourceManagementEndPoint) ?? DefaultVariables.ResourceManagementEndpoint; - var activeDirectoryEndpointBaseUri = - Environment.GetEnvironmentVariable(AccountVariables.ActiveDirectoryEndPoint) ?? DefaultVariables.ActiveDirectoryEndpoint; - - clientId = await ExternalVariables.Get(ExternalVariable.AzureSubscriptionClientId, cancellationToken); - clientSecret = await ExternalVariables.Get(ExternalVariable.AzureSubscriptionPassword, cancellationToken); - tenantId = await ExternalVariables.Get(ExternalVariable.AzureSubscriptionTenantId, cancellationToken); - subscriptionId = await ExternalVariables.Get(ExternalVariable.AzureSubscriptionId, cancellationToken); - - var resourceGroupLocation = Environment.GetEnvironmentVariable("AZURE_NEW_RESOURCE_REGION") ?? RandomAzureRegion.GetRandomRegionWithExclusions(); - - resourceGroupName = AzureTestResourceHelpers.GetResourceGroupName(); - - var servicePrincipalAccount = new AzureServicePrincipalAccount(subscriptionId, - clientId, - tenantId, - clientSecret, - "AzureGlobalCloud", - resourceManagementEndpointBaseUri, - activeDirectoryEndpointBaseUri); - - armClient = servicePrincipalAccount.CreateArmClient(retryOptions => - { - retryOptions.MaxRetries = 5; - retryOptions.Mode = RetryMode.Exponential; - retryOptions.Delay = TimeSpan.FromSeconds(2); - retryOptions.NetworkTimeout = TimeSpan.FromSeconds(200); - }); - - //create the resource group - subscriptionResource = armClient.GetSubscriptionResource(SubscriptionResource.CreateResourceIdentifier(subscriptionId)); - - var response = await subscriptionResource - .GetResourceGroups() - .CreateOrUpdateAsync(WaitUntil.Completed, - resourceGroupName, - new ResourceGroupData(new AzureLocation(resourceGroupLocation)) - { - Tags = - { - [AzureTestResourceHelpers.ResourceGroupTags.LifetimeInDaysKey] = AzureTestResourceHelpers.ResourceGroupTags.LifetimeInDaysValue, - [AzureTestResourceHelpers.ResourceGroupTags.SourceKey] = AzureTestResourceHelpers.ResourceGroupTags.SourceValue - } - }); - - resourceGroupResource = response.Value; - } - - [OneTimeTearDown] - public async Task Cleanup() - { - await armClient.GetResourceGroupResource(ResourceGroupResource.CreateResourceIdentifier(subscriptionId, resourceGroupName)) - .DeleteAsync(WaitUntil.Started); - } + readonly AzureResourceGroupFixture resourceGroupFixture = resourceGroupFixture; [Test] public async Task Deploy_with_template_in_package() @@ -192,19 +117,19 @@ await CommandTestBuilder.CreateAsync() .Execute(); } - private void AddDefaults(CommandTestBuilderContext context) + void AddDefaults(CommandTestBuilderContext context) { context.Variables.Add("Octopus.Account.AccountType", "AzureServicePrincipal"); - context.Variables.Add(AzureAccountVariables.SubscriptionId, subscriptionId); - context.Variables.Add(AzureAccountVariables.TenantId, tenantId); - context.Variables.Add(AzureAccountVariables.ClientId, clientId); - context.Variables.Add(AzureAccountVariables.Password, clientSecret); - context.Variables.Add(SpecialVariables.Action.Azure.ResourceGroupName, resourceGroupName); - context.Variables.Add("ResourceGroup", resourceGroupName); + context.Variables.Add(AzureAccountVariables.SubscriptionId, resourceGroupFixture.SubscriptionId); + context.Variables.Add(AzureAccountVariables.TenantId, resourceGroupFixture.TenantId); + context.Variables.Add(AzureAccountVariables.ClientId, resourceGroupFixture.ClientId); + context.Variables.Add(AzureAccountVariables.Password, resourceGroupFixture.ClientSecret); + context.Variables.Add(SpecialVariables.Action.Azure.ResourceGroupName, resourceGroupFixture.ResourceGroupName); + context.Variables.Add("ResourceGroup", resourceGroupFixture.ResourceGroupName); context.Variables.Add("SKU", "Shared"); //as we have a single resource group, we need to have unique web app name per test context.Variables.Add("WebSite", $"Calamari-{Guid.NewGuid():N}"); - context.Variables.Add("Location", resourceGroupResource.Data.Location); + context.Variables.Add("Location", resourceGroupFixture.ResourceGroupResource.Data.Location); //this is a storage account prefix, so just make it as random as possible //The names of the storage accounts are a max of 7 chars, so we generate a prefix of 17 chars (storage accounts have a max of 24) context.Variables.Add("AccountPrefix", AzureTestResourceHelpers.RandomName(length: 17)); diff --git a/source/Calamari.AzureResourceGroup.Tests/Calamari.AzureResourceGroup.Tests.csproj b/source/Calamari.AzureResourceGroup.Tests/Calamari.AzureResourceGroup.Tests.csproj index b1a3b5f0a9..dd9208b67d 100644 --- a/source/Calamari.AzureResourceGroup.Tests/Calamari.AzureResourceGroup.Tests.csproj +++ b/source/Calamari.AzureResourceGroup.Tests/Calamari.AzureResourceGroup.Tests.csproj @@ -9,11 +9,14 @@ true - - - + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/source/Calamari.AzureResourceGroup.Tests/CalamariTest.cs b/source/Calamari.AzureResourceGroup.Tests/CalamariTest.cs new file mode 100644 index 0000000000..24a1a79a93 --- /dev/null +++ b/source/Calamari.AzureResourceGroup.Tests/CalamariTest.cs @@ -0,0 +1,18 @@ +using System; +using System.Threading; + +namespace Calamari.AzureResourceGroup.Tests; + +public abstract class CalamariTest +{ + readonly CancellationTokenSource cancellationTokenSource; + protected CancellationToken CancellationToken => cancellationTokenSource.Token; + + protected virtual TimeSpan DefaultTestTimeout => TimeSpan.MaxValue; + + protected CalamariTest() + { + var ctsTimeout = new CancellationTokenSource(DefaultTestTimeout); + cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(ctsTimeout.Token, TestContext.Current.CancellationToken); + } +} \ No newline at end of file diff --git a/source/Calamari.AzureResourceGroup.Tests/DeployAzureBicepTemplateCommandFixture.cs b/source/Calamari.AzureResourceGroup.Tests/DeployAzureBicepTemplateCommandFixture.cs index 1bd5c2213f..3b0188a910 100644 --- a/source/Calamari.AzureResourceGroup.Tests/DeployAzureBicepTemplateCommandFixture.cs +++ b/source/Calamari.AzureResourceGroup.Tests/DeployAzureBicepTemplateCommandFixture.cs @@ -1,97 +1,25 @@ using System; using System.IO; -using System.Threading; using System.Threading.Tasks; -using Azure; -using Azure.Core; -using Azure.ResourceManager; -using Azure.ResourceManager.Resources; -using Calamari.Azure; -using Calamari.CloudAccounts; +using Calamari.AzureResourceGroup.Tests.Support; using Calamari.Testing; using Calamari.Testing.Azure; using Calamari.Testing.Helpers; using Calamari.Testing.Tools; -using NUnit.Framework; namespace Calamari.AzureResourceGroup.Tests { - [TestFixture] - [Category(TestCategory.CompatibleOS.OnlyWindows)] - class DeployAzureBicepTemplateCommandFixture + [TestPlatforms(TestCategory.CompatibleOS.OnlyWindows)] + [Collection(nameof(AzureResourceGroupFixture))] + public class DeployAzureBicepTemplateCommandFixture(AzureResourceGroupFixture resourceGroupFixture) : CalamariTest { - string clientId; - string clientSecret; - string tenantId; - string subscriptionId; - string resourceGroupName; - string resourceGroupLocation; - ArmClient armClient; - static readonly CancellationTokenSource CancellationTokenSource = new CancellationTokenSource(TimeSpan.FromMinutes(5)); - readonly CancellationToken cancellationToken = CancellationTokenSource.Token; + readonly AzureResourceGroupFixture resourceGroupFixture = resourceGroupFixture; + readonly string packagePath = TestEnvironment.GetTestPath("Packages", "Bicep"); - SubscriptionResource subscriptionResource; static IDeploymentTool AzureCLI = new InPathDeploymentTool("Octopus.Dependencies.AzureCLI", "AzureCLI\\wbin"); - [OneTimeSetUp] - public async Task Setup() - { - var resourceManagementEndpointBaseUri = - Environment.GetEnvironmentVariable(AccountVariables.ResourceManagementEndPoint) ?? DefaultVariables.ResourceManagementEndpoint; - var activeDirectoryEndpointBaseUri = - Environment.GetEnvironmentVariable(AccountVariables.ActiveDirectoryEndPoint) ?? DefaultVariables.ActiveDirectoryEndpoint; - - clientId = await ExternalVariables.Get(ExternalVariable.AzureSubscriptionClientId, cancellationToken); - clientSecret = await ExternalVariables.Get(ExternalVariable.AzureSubscriptionPassword, cancellationToken); - tenantId = await ExternalVariables.Get(ExternalVariable.AzureSubscriptionTenantId, cancellationToken); - subscriptionId = await ExternalVariables.Get(ExternalVariable.AzureSubscriptionId, cancellationToken); - - resourceGroupName = AzureTestResourceHelpers.GetResourceGroupName(); - - resourceGroupLocation = Environment.GetEnvironmentVariable("AZURE_NEW_RESOURCE_REGION") ?? RandomAzureRegion.GetRandomRegionWithExclusions(); - - var servicePrincipalAccount = new AzureServicePrincipalAccount(subscriptionId, - clientId, - tenantId, - clientSecret, - "AzureGlobalCloud", - resourceManagementEndpointBaseUri, - activeDirectoryEndpointBaseUri); - - armClient = servicePrincipalAccount.CreateArmClient(retryOptions => - { - retryOptions.MaxRetries = 5; - retryOptions.Mode = RetryMode.Exponential; - retryOptions.Delay = TimeSpan.FromSeconds(2); - retryOptions.NetworkTimeout = TimeSpan.FromSeconds(200); - }); - - //create the resource group - subscriptionResource = armClient.GetSubscriptionResource(SubscriptionResource.CreateResourceIdentifier(subscriptionId)); - - await subscriptionResource - .GetResourceGroups() - .CreateOrUpdateAsync(WaitUntil.Completed, - resourceGroupName, - new ResourceGroupData(new AzureLocation(resourceGroupLocation)) - { - Tags = - { - [AzureTestResourceHelpers.ResourceGroupTags.LifetimeInDaysKey] = AzureTestResourceHelpers.ResourceGroupTags.LifetimeInDaysValue, - [AzureTestResourceHelpers.ResourceGroupTags.SourceKey] = AzureTestResourceHelpers.ResourceGroupTags.SourceValue - } - }); - } - - [OneTimeTearDown] - public async Task Cleanup() - { - await armClient.GetResourceGroupResource(ResourceGroupResource.CreateResourceIdentifier(subscriptionId, resourceGroupName)) - .DeleteAsync(WaitUntil.Started); - } - - [Test] + [Fact] public async Task DeployAzureBicepTemplate_PackageSource() { await CommandTestBuilder.CreateAsync() @@ -105,7 +33,7 @@ await CommandTestBuilder.CreateAsync() .Execute(); } - [Test] + [Fact] public async Task DeployAzureBicepTemplate_GitSource() { // For the purposes of Bicep templates in Calamari, a template in a Git Repository @@ -123,11 +51,11 @@ await CommandTestBuilder.CreateAsync() .Execute(); } - [Test] + [Fact] public async Task DeployAzureBicepTemplate_InlineSource() { - var templateFileContent = File.ReadAllText(Path.Combine(packagePath, "azure_website_template.bicep")); - var paramsFileContent = File.ReadAllText(Path.Combine(packagePath, "parameters.json")); + var templateFileContent = await File.ReadAllTextAsync(Path.Combine(packagePath, "azure_website_template.bicep"), CancellationToken); + var paramsFileContent = await File.ReadAllTextAsync(Path.Combine(packagePath, "parameters.json"), CancellationToken); await CommandTestBuilder.CreateAsync() .WithArrange(context => @@ -145,17 +73,17 @@ void AddDefaults(CommandTestBuilderContext context) context.WithTool(AzureCLI); context.Variables.Add(AzureScripting.SpecialVariables.Account.AccountType, "AzureServicePrincipal"); - context.Variables.Add(AzureAccountVariables.SubscriptionId, subscriptionId); - context.Variables.Add(AzureAccountVariables.TenantId, tenantId); - context.Variables.Add(AzureAccountVariables.ClientId, clientId); - context.Variables.Add(AzureAccountVariables.Password, clientSecret); - context.Variables.Add(SpecialVariables.Action.Azure.ResourceGroupName, resourceGroupName); - context.Variables.Add(SpecialVariables.Action.Azure.ResourceGroupLocation, resourceGroupLocation); + context.Variables.Add(AzureAccountVariables.SubscriptionId, resourceGroupFixture.SubscriptionId); + context.Variables.Add(AzureAccountVariables.TenantId, resourceGroupFixture.TenantId); + context.Variables.Add(AzureAccountVariables.ClientId, resourceGroupFixture.ClientId); + context.Variables.Add(AzureAccountVariables.Password, resourceGroupFixture.ClientSecret); + context.Variables.Add(SpecialVariables.Action.Azure.ResourceGroupName, resourceGroupFixture.ResourceGroupName); + context.Variables.Add(SpecialVariables.Action.Azure.ResourceGroupLocation, resourceGroupFixture.ResourceGroupLocation); context.Variables.Add(SpecialVariables.Action.Azure.ResourceGroupDeploymentMode, "Complete"); context.Variables.Add(SpecialVariables.Action.Azure.TemplateParameters, "parameters.json"); context.Variables.Add("SKU", "Standard_LRS"); - context.Variables.Add("Location", resourceGroupLocation); + context.Variables.Add("Location", resourceGroupFixture.ResourceGroupLocation); //storage accounts can be 24 chars long context.Variables.Add("StorageAccountName", AzureTestResourceHelpers.RandomName(length: 24)); } diff --git a/source/Calamari.AzureResourceGroup.Tests/DeploymentNameFixture.cs b/source/Calamari.AzureResourceGroup.Tests/DeploymentNameTests.cs similarity index 52% rename from source/Calamari.AzureResourceGroup.Tests/DeploymentNameFixture.cs rename to source/Calamari.AzureResourceGroup.Tests/DeploymentNameTests.cs index 1ec80b6227..8f152acb9c 100644 --- a/source/Calamari.AzureResourceGroup.Tests/DeploymentNameFixture.cs +++ b/source/Calamari.AzureResourceGroup.Tests/DeploymentNameTests.cs @@ -1,42 +1,42 @@ -using NUnit.Framework; - -namespace Calamari.AzureResourceGroup.Tests -{ - [TestFixture] - public class DeploymentNameFixture +namespace Calamari.AzureResourceGroup.Tests +{ public class DeploymentNameFixture { - [Test] + [Fact] public void GivenShortStepName_Then_Can_Generate_Deployment_Name_Appropriately() { // Given / When var deploymentName = DeploymentName.FromStepName("StepA"); // Then - Assert.That(deploymentName, Has.Length.LessThanOrEqualTo(64)); - Assert.That(deploymentName, Has.Length.EqualTo(38)); - Assert.That(deploymentName, Does.StartWith("stepa-")); + deploymentName.Should() + .HaveLength(38) + .And + .StartWith("stepa-"); } - [Test] + [Fact] public void GivenNormalStepName_Then_Can_Generate_Deployment_Name_Appropriately() { // Given / When var deploymentName = DeploymentName.FromStepName("1234567890123456789012345678901"); // 31 chars // Then - Assert.That(deploymentName, Has.Length.EqualTo(64)); - Assert.That(deploymentName, Does.StartWith("1234567890123456789012345678901-")); + deploymentName.Should().HaveLength(64) + .And + .StartWith("1234567890123456789012345678901-"); } - [Test] + [Fact] public void GivenLongStepName_Then_Can_Generate_Deployment_Name_Appropriately() { // Given / When var deploymentName = DeploymentName.FromStepName("1234567890123456789012345678901234567890"); // 40 chars // Then - Assert.That(deploymentName, Has.Length.EqualTo(64)); - Assert.That(deploymentName, Does.StartWith("1234567890123456789012345678901-")); // 27 Characters Allow + deploymentName.Should() + .HaveLength(64) + .And + .StartWith("1234567890123456789012345678901-"); // 27 Characters Allow } } } \ No newline at end of file diff --git a/source/Calamari.AzureResourceGroup.Tests/GlobalUsings.cs b/source/Calamari.AzureResourceGroup.Tests/GlobalUsings.cs new file mode 100644 index 0000000000..cbd65c225a --- /dev/null +++ b/source/Calamari.AzureResourceGroup.Tests/GlobalUsings.cs @@ -0,0 +1,4 @@ +global using Xunit; +global using FluentAssertions; +global using FluentAssertions.Execution; +global using TestContext = Xunit.TestContext; \ No newline at end of file diff --git a/source/Calamari.AzureResourceGroup.Tests/Support/AzureResourceGroupFixture.cs b/source/Calamari.AzureResourceGroup.Tests/Support/AzureResourceGroupFixture.cs new file mode 100644 index 0000000000..df35052484 --- /dev/null +++ b/source/Calamari.AzureResourceGroup.Tests/Support/AzureResourceGroupFixture.cs @@ -0,0 +1,88 @@ +using System; +using System.Threading.Tasks; +using Azure; +using Azure.Core; +using Azure.ResourceManager; +using Azure.ResourceManager.Resources; +using Calamari.Azure; +using Calamari.CloudAccounts; +using Calamari.Testing; +using Calamari.Testing.Azure; + +namespace Calamari.AzureResourceGroup.Tests.Support; + +public class AzureResourceGroupFixture : IAsyncLifetime +{ + ArmClient armClient; + SubscriptionResource subscriptionResource; + + public string ClientId { get; private set; } + public string ClientSecret { get; private set; } + public string SubscriptionId { get; private set; } + public string TenantId { get; private set; } + + public string ResourceGroupName { get; private set; } + public string ResourceGroupLocation { get; private set; } + public ResourceGroupResource ResourceGroupResource { get; private set; } + + + public async ValueTask InitializeAsync() + { + var resourceManagementEndpointBaseUri = + Environment.GetEnvironmentVariable(AccountVariables.ResourceManagementEndPoint) ?? DefaultVariables.ResourceManagementEndpoint; + var activeDirectoryEndpointBaseUri = + Environment.GetEnvironmentVariable(AccountVariables.ActiveDirectoryEndPoint) ?? DefaultVariables.ActiveDirectoryEndpoint; + + ClientId = await ExternalVariables.Get(ExternalVariable.AzureSubscriptionClientId, TestContext.Current.CancellationToken); + ClientSecret = await ExternalVariables.Get(ExternalVariable.AzureSubscriptionPassword, TestContext.Current.CancellationToken); + TenantId = await ExternalVariables.Get(ExternalVariable.AzureSubscriptionTenantId, TestContext.Current.CancellationToken); + SubscriptionId = await ExternalVariables.Get(ExternalVariable.AzureSubscriptionId, TestContext.Current.CancellationToken); + + ResourceGroupName = AzureTestResourceHelpers.GetResourceGroupName(); + + ResourceGroupLocation = Environment.GetEnvironmentVariable("AZURE_NEW_RESOURCE_REGION") ?? RandomAzureRegion.GetRandomRegionWithExclusions(); + + var servicePrincipalAccount = new AzureServicePrincipalAccount(SubscriptionId, + ClientId, + TenantId, + ClientSecret, + "AzureGlobalCloud", + resourceManagementEndpointBaseUri, + activeDirectoryEndpointBaseUri); + + armClient = servicePrincipalAccount.CreateArmClient(retryOptions => + { + retryOptions.MaxRetries = 5; + retryOptions.Mode = RetryMode.Exponential; + retryOptions.Delay = TimeSpan.FromSeconds(2); + retryOptions.NetworkTimeout = TimeSpan.FromSeconds(200); + }); + + //create the resource group + subscriptionResource = armClient.GetSubscriptionResource(SubscriptionResource.CreateResourceIdentifier(SubscriptionId)); + + var response = await subscriptionResource + .GetResourceGroups() + .CreateOrUpdateAsync(WaitUntil.Completed, + ResourceGroupName, + new ResourceGroupData(new AzureLocation(ResourceGroupLocation)) + { + Tags = + { + [AzureTestResourceHelpers.ResourceGroupTags.LifetimeInDaysKey] = AzureTestResourceHelpers.ResourceGroupTags.LifetimeInDaysValue, + [AzureTestResourceHelpers.ResourceGroupTags.SourceKey] = AzureTestResourceHelpers.ResourceGroupTags.SourceValue + } + }); + + ResourceGroupResource = response.Value; + } + + public async ValueTask DisposeAsync() + { + await armClient.GetResourceGroupResource(ResourceGroupResource.CreateResourceIdentifier(SubscriptionId, ResourceGroupResource.Data.Name)) + .DeleteAsync(WaitUntil.Started, cancellationToken: TestContext.Current.CancellationToken); + } +} + +[CollectionDefinition(nameof(AzureResourceGroupFixture))] +public class AzureResourceGroupCollection : ICollectionFixture; \ No newline at end of file diff --git a/source/Calamari.AzureResourceGroup.Tests/TestPlatformsAttribute.cs b/source/Calamari.AzureResourceGroup.Tests/TestPlatformsAttribute.cs new file mode 100644 index 0000000000..f7a9896bdd --- /dev/null +++ b/source/Calamari.AzureResourceGroup.Tests/TestPlatformsAttribute.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using Xunit.v3; + +namespace Calamari.AzureResourceGroup.Tests; + +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] +public class TestPlatformsAttribute(string platform) : Attribute, ITraitAttribute +{ + public string Platform { get; } = platform; + + public IReadOnlyCollection> GetTraits() + => [new("Category", Platform)]; +} \ No newline at end of file From 29d7dbc5eee705a877f144646f9105b9d97eed30 Mon Sep 17 00:00:00 2001 From: Alastair Pitts Date: Thu, 8 Jan 2026 17:33:40 +1100 Subject: [PATCH 21/22] Remove some nunit attributes --- .../TestPlatformsAttribute.cs | 2 +- .../AzureResourceGroupActionHandlerTests.cs | 21 ++++++++++++------- .../CalamariTest.cs | 4 ++-- ...> DeployAzureBicepTemplateCommandTests.cs} | 5 ++++- .../DeploymentNameTests.cs | 3 ++- 5 files changed, 23 insertions(+), 12 deletions(-) rename source/Calamari.AzureResourceGroup.Tests/{ => Attributes}/TestPlatformsAttribute.cs (87%) rename source/Calamari.AzureResourceGroup.Tests/{DeployAzureBicepTemplateCommandFixture.cs => DeployAzureBicepTemplateCommandTests.cs} (95%) diff --git a/source/Calamari.AzureResourceGroup.Tests/TestPlatformsAttribute.cs b/source/Calamari.AzureResourceGroup.Tests/Attributes/TestPlatformsAttribute.cs similarity index 87% rename from source/Calamari.AzureResourceGroup.Tests/TestPlatformsAttribute.cs rename to source/Calamari.AzureResourceGroup.Tests/Attributes/TestPlatformsAttribute.cs index f7a9896bdd..5d8f208351 100644 --- a/source/Calamari.AzureResourceGroup.Tests/TestPlatformsAttribute.cs +++ b/source/Calamari.AzureResourceGroup.Tests/Attributes/TestPlatformsAttribute.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using Xunit.v3; -namespace Calamari.AzureResourceGroup.Tests; +namespace Calamari.AzureResourceGroup.Tests.Attributes; [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class TestPlatformsAttribute(string platform) : Attribute, ITraitAttribute diff --git a/source/Calamari.AzureResourceGroup.Tests/AzureResourceGroupActionHandlerTests.cs b/source/Calamari.AzureResourceGroup.Tests/AzureResourceGroupActionHandlerTests.cs index 5fa1da9e0c..568fb19201 100644 --- a/source/Calamari.AzureResourceGroup.Tests/AzureResourceGroupActionHandlerTests.cs +++ b/source/Calamari.AzureResourceGroup.Tests/AzureResourceGroupActionHandlerTests.cs @@ -1,9 +1,11 @@ using System; using System.IO; using System.Threading.Tasks; +using Calamari.AzureResourceGroup.Tests.Attributes; using Calamari.AzureResourceGroup.Tests.Support; using Calamari.Common.Features.Deployment; using Calamari.Common.Features.Scripts; +using Calamari.Common.Plumbing.Extensions; using Calamari.Common.Plumbing.Variables; using Calamari.Testing; using Calamari.Testing.Azure; @@ -11,17 +13,18 @@ using Calamari.Testing.Requirements; using Newtonsoft.Json.Linq; using NUnit.Framework; +using Xunit.Sdk; // ReSharper disable MethodHasAsyncOverload - File.ReadAllTextAsync does not exist for .net framework targets namespace Calamari.AzureResourceGroup.Tests { [Collection(nameof(AzureResourceGroupFixture))] - public class AzureResourceGroupActionHandlerFixture(AzureResourceGroupFixture resourceGroupFixture): CalamariTest + public class AzureResourceGroupActionHandlerTests(AzureResourceGroupFixture resourceGroupFixture): CalamariTest { readonly AzureResourceGroupFixture resourceGroupFixture = resourceGroupFixture; - [Test] + [Fact] public async Task Deploy_with_template_in_package() { var packagePath = TestEnvironment.GetTestPath("Packages", "AzureResourceGroup"); @@ -38,7 +41,7 @@ await CommandTestBuilder.CreateAsync() .Execute(); } - [Test] + [Fact] public async Task Deploy_with_template_in_git_repository() { // For the purposes of ARM templates in Calamari, a template in a Git Repository @@ -59,7 +62,7 @@ await CommandTestBuilder.CreateAsync() .Execute(); } - [Test] + [Fact] public async Task Deploy_with_template_inline() { var packagePath = TestEnvironment.GetTestPath("Packages", "AzureResourceGroup"); @@ -83,11 +86,15 @@ await CommandTestBuilder.CreateAsync() .Execute(); } - [Test] - [WindowsTest] - [RequiresPowerShell5OrAbove] + [Fact] + [TestPlatforms(TestCategory.CompatibleOS.OnlyWindows)] public async Task Deploy_Ensure_Tools_Are_Configured() { + if (ScriptingEnvironment.SafelyGetPowerShellVersion().Major < 5) + { + throw SkipException.ForSkip("This test requires PowerShell 5 or above."); + } + var packagePath = TestEnvironment.GetTestPath("Packages", "AzureResourceGroup"); var templateFileContent = File.ReadAllText(Path.Combine(packagePath, "azure_website_template.json")); var paramsFileContent = File.ReadAllText(Path.Combine(packagePath, "azure_website_params.json")); diff --git a/source/Calamari.AzureResourceGroup.Tests/CalamariTest.cs b/source/Calamari.AzureResourceGroup.Tests/CalamariTest.cs index 24a1a79a93..1438f390e3 100644 --- a/source/Calamari.AzureResourceGroup.Tests/CalamariTest.cs +++ b/source/Calamari.AzureResourceGroup.Tests/CalamariTest.cs @@ -8,11 +8,11 @@ public abstract class CalamariTest readonly CancellationTokenSource cancellationTokenSource; protected CancellationToken CancellationToken => cancellationTokenSource.Token; - protected virtual TimeSpan DefaultTestTimeout => TimeSpan.MaxValue; + protected virtual TimeSpan TestTimeout => TimeSpan.MaxValue; protected CalamariTest() { - var ctsTimeout = new CancellationTokenSource(DefaultTestTimeout); + var ctsTimeout = new CancellationTokenSource(TestTimeout); cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(ctsTimeout.Token, TestContext.Current.CancellationToken); } } \ No newline at end of file diff --git a/source/Calamari.AzureResourceGroup.Tests/DeployAzureBicepTemplateCommandFixture.cs b/source/Calamari.AzureResourceGroup.Tests/DeployAzureBicepTemplateCommandTests.cs similarity index 95% rename from source/Calamari.AzureResourceGroup.Tests/DeployAzureBicepTemplateCommandFixture.cs rename to source/Calamari.AzureResourceGroup.Tests/DeployAzureBicepTemplateCommandTests.cs index 3b0188a910..7a71f23b11 100644 --- a/source/Calamari.AzureResourceGroup.Tests/DeployAzureBicepTemplateCommandFixture.cs +++ b/source/Calamari.AzureResourceGroup.Tests/DeployAzureBicepTemplateCommandTests.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Threading.Tasks; +using Calamari.AzureResourceGroup.Tests.Attributes; using Calamari.AzureResourceGroup.Tests.Support; using Calamari.Testing; using Calamari.Testing.Azure; @@ -11,7 +12,7 @@ namespace Calamari.AzureResourceGroup.Tests { [TestPlatforms(TestCategory.CompatibleOS.OnlyWindows)] [Collection(nameof(AzureResourceGroupFixture))] - public class DeployAzureBicepTemplateCommandFixture(AzureResourceGroupFixture resourceGroupFixture) : CalamariTest + public class DeployAzureBicepTemplateCommandTests(AzureResourceGroupFixture resourceGroupFixture) : CalamariTest { readonly AzureResourceGroupFixture resourceGroupFixture = resourceGroupFixture; @@ -19,6 +20,8 @@ public class DeployAzureBicepTemplateCommandFixture(AzureResourceGroupFixture re static IDeploymentTool AzureCLI = new InPathDeploymentTool("Octopus.Dependencies.AzureCLI", "AzureCLI\\wbin"); + protected override TimeSpan TestTimeout => TimeSpan.FromMinutes(5); + [Fact] public async Task DeployAzureBicepTemplate_PackageSource() { diff --git a/source/Calamari.AzureResourceGroup.Tests/DeploymentNameTests.cs b/source/Calamari.AzureResourceGroup.Tests/DeploymentNameTests.cs index 8f152acb9c..6f58985c24 100644 --- a/source/Calamari.AzureResourceGroup.Tests/DeploymentNameTests.cs +++ b/source/Calamari.AzureResourceGroup.Tests/DeploymentNameTests.cs @@ -1,5 +1,6 @@ namespace Calamari.AzureResourceGroup.Tests -{ public class DeploymentNameFixture +{ + public class DeploymentNameTests { [Fact] public void GivenShortStepName_Then_Can_Generate_Deployment_Name_Appropriately() From 03fc55e4092c99c1d151cf0d24c3771ebbc3f9e5 Mon Sep 17 00:00:00 2001 From: Alastair Pitts Date: Fri, 9 Jan 2026 09:35:36 +1100 Subject: [PATCH 22/22] Fix default test timeout --- source/Calamari.AzureResourceGroup.Tests/CalamariTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/Calamari.AzureResourceGroup.Tests/CalamariTest.cs b/source/Calamari.AzureResourceGroup.Tests/CalamariTest.cs index 1438f390e3..bf09cc5563 100644 --- a/source/Calamari.AzureResourceGroup.Tests/CalamariTest.cs +++ b/source/Calamari.AzureResourceGroup.Tests/CalamariTest.cs @@ -8,7 +8,7 @@ public abstract class CalamariTest readonly CancellationTokenSource cancellationTokenSource; protected CancellationToken CancellationToken => cancellationTokenSource.Token; - protected virtual TimeSpan TestTimeout => TimeSpan.MaxValue; + protected virtual TimeSpan TestTimeout => TimeSpan.FromMilliseconds(int.MaxValue); protected CalamariTest() {