diff --git a/.github/workflows/Develop.yml b/.github/workflows/Build.yml similarity index 68% rename from .github/workflows/Develop.yml rename to .github/workflows/Build.yml index 93a6070..3918b90 100644 --- a/.github/workflows/Develop.yml +++ b/.github/workflows/Build.yml @@ -1,21 +1,20 @@ # ------------------------------------------------------------------------------ -# Develop.yml +# Build.yml # ------------------------------------------------------------------------------ -name: Develop +name: Build on: push: - branches-ignore: - - master pull_request: branches-ignore: - master + - main workflow_dispatch: jobs: - Develop: - name: Develop + Build: + name: Build runs-on: windows-latest steps: - uses: actions/checkout@v1 @@ -28,5 +27,7 @@ jobs: NugetApiUrl: ${{ secrets.NUGET_API_URL }} NugetApiKey: ${{ secrets.NUGET_API_KEY }} - SignFile: ${{ secrets.SIGN_FILE }} - SignPassword: ${{ secrets.SIGN_PASSWORD }} \ No newline at end of file + # SignFile: ${{ secrets.SIGN_FILE }} + # SignPassword: ${{ secrets.SIGN_PASSWORD }} + SignFile: ${{ secrets.SIGN_FILE_AZURE }} + SignPassword: ${{ secrets.SIGN_PASSWORD_AZURE }} \ No newline at end of file diff --git a/.github/workflows/Publish.yml b/.github/workflows/Publish.yml deleted file mode 100644 index eeb8fc3..0000000 --- a/.github/workflows/Publish.yml +++ /dev/null @@ -1,29 +0,0 @@ -# ------------------------------------------------------------------------------ -# Publish.yml -# ------------------------------------------------------------------------------ - -name: Publish - -on: - push: - branches: - - master - workflow_dispatch: - -jobs: - Publish: - name: Publish - runs-on: windows-latest - steps: - - uses: actions/checkout@v1 - - - name: Run './build/build.cmd' - run: ./build/build.cmd --root ./build - env: - GitHubToken: ${{ secrets.GITHUB_TOKEN }} - - NugetApiUrl: ${{ secrets.NUGET_API_URL }} - NugetApiKey: ${{ secrets.NUGET_API_KEY }} - - SignFile: ${{ secrets.SIGN_FILE }} - SignPassword: ${{ secrets.SIGN_PASSWORD }} \ No newline at end of file diff --git a/Build/.nuke/.gitignore b/Build/.nuke/.gitignore new file mode 100644 index 0000000..9c595a6 --- /dev/null +++ b/Build/.nuke/.gitignore @@ -0,0 +1 @@ +temp diff --git a/Build/.nuke/build.schema.json b/Build/.nuke/build.schema.json index a9c9453..9454c2f 100644 --- a/Build/.nuke/build.schema.json +++ b/Build/.nuke/build.schema.json @@ -24,12 +24,14 @@ "ExecutableTarget": { "type": "string", "enum": [ + "AzureSignTool", "Build", "Clean", "Compile", "CompileExample", "GitPreRelease", "GitRelease", + "LocalAssetRelease", "Pack", "PrePack", "Release", @@ -109,6 +111,9 @@ "allOf": [ { "properties": { + "EnableForkedRepository": { + "type": "boolean" + }, "Folder": { "type": "string" }, diff --git a/Build/Build.cs b/Build/Build.cs index 45a473b..76c5658 100644 --- a/Build/Build.cs +++ b/Build/Build.cs @@ -3,8 +3,10 @@ using ricaun.Nuke; using ricaun.Nuke.Components; -class Build : NukeBuild, IPublishPack, ICompileExample, ITest, IShowGitVersion, IPrePack +class Build : NukeBuild, IPublishPack, ICompileExample, ITest, IShowGitVersion, IAzureSignTool, IPrePack, ILocalAssetRelease { + public void ReleaseAsset(ReleaseAssets releaseAssets) { } + IAssetRelease IHazAssetRelease.AssetRelease => new AssetRelease(); //bool IPack.UnlistNuget => true; bool ITest.TestBuildStopWhenFailed => false; public static int Main() => Execute(x => x.From().Build); diff --git a/Build/Build.csproj b/Build/Build.csproj index 36e6397..736a54d 100644 --- a/Build/Build.csproj +++ b/Build/Build.csproj @@ -18,4 +18,5 @@ + diff --git a/Build/IAzureSignTool.cs b/Build/IAzureSignTool.cs new file mode 100644 index 0000000..5ddaa70 --- /dev/null +++ b/Build/IAzureSignTool.cs @@ -0,0 +1,18 @@ +using Nuke.Common; +using Nuke.Common.Tools.AzureSignTool; +using ricaun.Nuke.Components; +using ricaun.Nuke.Tools.NuGetKeyVaultSignTool; + +public interface IAzureSignTool : IClean, ICompile +{ + Target AzureSignTool => _ => _ + .TriggeredBy(Clean) + .Before(Compile) + .Executes(() => + { + ricaun.Nuke.Tools.AzureSignToolUtils.EnsureAzureToolIsInstalled(); + + Serilog.Log.Information(AzureSignToolTasks.AzureSignToolPath); + Serilog.Log.Information(NuGetKeyVaultSignToolTasks.NuGetKeyVaultSignToolPath); + }); +} diff --git a/Build/ILocalAssetRelease.cs b/Build/ILocalAssetRelease.cs new file mode 100644 index 0000000..197fcc6 --- /dev/null +++ b/Build/ILocalAssetRelease.cs @@ -0,0 +1,35 @@ +using Nuke.Common; +using ricaun.Nuke.Components; +using ricaun.Nuke.Extensions; + +class AssetRelease : IAssetRelease +{ + public void ReleaseAsset(ReleaseAssets releaseAssets) + { + Serilog.Log.Information($"Project: {releaseAssets.Project.Name}"); + Serilog.Log.Information($"Version: {releaseAssets.Version}"); + Serilog.Log.Information($"Notes: {releaseAssets.Notes}"); + Serilog.Log.Information($"Prerelease: {releaseAssets.Prerelease}"); + foreach (var file in releaseAssets.Assets) + { + Serilog.Log.Information($"File: {file}"); + } + } +} + +public interface ILocalAssetRelease : IClean, ICompile, IHazAssetRelease, IAssetRelease +{ + Target LocalAssetRelease => _ => _ + .TriggeredBy(Clean) + .Before(Compile) + .Executes(() => + { + var releaseAssets = new ReleaseAssets + { + Project = MainProject, + Version = "0.0.0", + Notes = "Release Notes", + }; + ExecuteReleaseAsset(releaseAssets); + }); +} diff --git a/Build/IShowGitVersion.cs b/Build/IShowGitVersion.cs index 490251e..c76782c 100644 --- a/Build/IShowGitVersion.cs +++ b/Build/IShowGitVersion.cs @@ -1,8 +1,9 @@ using Nuke.Common; +using Nuke.Common.Git; using ricaun.Nuke.Components; using ricaun.Nuke.Extensions; -public interface IShowGitVersion : IHazGitVersion, IHazChangelog, IClean, ICompile +public interface IShowGitVersion : IHazGitVersion, IHazGitRepository, IHazChangelog, IClean, ICompile { Target ShowGitVersion => _ => _ .TriggeredBy(Clean) @@ -23,5 +24,23 @@ public interface IShowGitVersion : IHazGitVersion, IHazChangelog, IClean, ICompi System.IO.Path.Combine(BuildAssemblyDirectory, $"latest.json")); } catch { } + + + Serilog.Log.Information("Commit = {Value}", GitRepository.Commit); + Serilog.Log.Information("Branch = {Value}", GitRepository.Branch); + Serilog.Log.Information("Tags = {Value}", GitRepository.Tags); + Serilog.Log.Information("Head = {Value}", GitRepository.Head); + Serilog.Log.Information("Identifier = {Value}", GitRepository.Identifier); + + Serilog.Log.Information("IsForked = {Value}", GitRepository.IsForked()); + + Serilog.Log.Information("main branch = {Value}", GitRepository.IsOnMainBranch()); + Serilog.Log.Information("main/master branch = {Value}", GitRepository.IsOnMainOrMasterBranch()); + Serilog.Log.Information("release/* branch = {Value}", GitRepository.IsOnReleaseBranch()); + Serilog.Log.Information("hotfix/* branch = {Value}", GitRepository.IsOnHotfixBranch()); + + Serilog.Log.Information("Https URL = {Value}", GitRepository.HttpsUrl); + Serilog.Log.Information("SSH URL = {Value}", GitRepository.SshUrl); + }); } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 5048731..258cd60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,39 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [1.9.0] / 2024-12-06 - 2024-12-19 +### Features +- Enable sign files using `Azure Key Vault`. +- Enable `IAssetRelease` to release assets before `GitRelease` and `GitPreRelease`. +- Enable `SkipForked` to skip release if forked repository. +### Build +- Add `IAzureSignTool` to check if `AzureSignToolUtils` is installed. +- Add `ILocalAssetRelease` to test `AssetRelease` assets before release. +### Updates +- Add version `Information` in the `CommonExtension`. +- Add `AzureSignToolUtils` to sign files using `AzureSignToolTasks` or `NuGetKeyVaultSignToolTasks`. +- Add `NuGetKeyVaultSignTool` for nuke version `8.*`. +- Add `AzureKeyVaultConfig` with json file with `Azure Key Vault` without secrets. +- Add `PackageDownload` to download `AzureSignTool` and `NuGetKeyVaultSignTool` on the fly. +- Add `HttpAuthTasks` to get/post files. +- Update `HttpAuthTasks` docs. +- Update `IsPathTooLong` to equal or greater than `260`. +- Update `SignExtension.Sign` to sign NuGet or files. +- Update `SignProject` to sign files using `Azure Key Vault` if available. +- Update `GetToolInstallationPath` to use user temp folder. +- Update `TestRunUtil` icons to circle with color. +- Update `AzureSignToolUtils` sign to ignore exception. +- Update `AzureSignToolUtils` to ignore if file is already signed. +- Update `HasSignature` to use `PathTooLongUtils` to check if file is signed. (Fix: #77) +- Update `ExecuteReleaseAsset` to execute `IHazAssetRelease` and build with `IAssetRelease` +### Example +- Add `Resource` and `Resource.pt-BR` to test sign files. +### Tests +- Update `NuGetExtensionTests` +- Add `AzureKeyVaultConfigTests` + ## [1.8.2] / 2024-11-20 -### Update +### Updates - Update `Nuke.Common` to `8.1.4`. - Update `FileSystemTasks.CopyFileToDirectory` to `AbsolutePathExtensions.CopyToDirectory`. - Update `FileSystemTasks.CopyDirectoryRecursively` to `AbsolutePathExtensions.Copy`. @@ -358,6 +389,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - First Release [vNext]: ../../compare/1.0.0...HEAD +[1.9.0]: ../../compare/1.8.2...1.9.0 [1.8.2]: ../../compare/1.8.1...1.8.2 [1.8.1]: ../../compare/1.8.0...1.8.1 [1.8.0]: ../../compare/1.7.4...1.8.0 diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 0000000..3af54d3 --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,5 @@ + + + 1.9.0 + + \ No newline at end of file diff --git a/README.md b/README.md index 3bb8bac..f164c83 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ This package is to simplify the build automation system using [Nuke.Common](http [![Visual Studio 2022](https://img.shields.io/badge/Visual%20Studio-2022-blue)](../..) [![Nuke](https://img.shields.io/badge/Nuke-Build-blue)](https://nuke.build/) [![License MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) -[![Publish](https://github.com/ricaun-io/ricaun.Nuke/actions/workflows/Publish.yml/badge.svg)](https://github.com/ricaun-io/ricaun.Nuke/actions) +[![Build](https://github.com/ricaun-io/ricaun.Nuke/actions/workflows/Build.yml/badge.svg)](https://github.com/ricaun-io/ricaun.Nuke/actions) [![Release](https://img.shields.io/nuget/v/ricaun.Nuke?logo=nuget&label=release&color=blue)](https://www.nuget.org/packages/ricaun.Nuke) # Examples @@ -51,7 +51,14 @@ class Build : NukeBuild, IPublishPack ## Environment Variables -### Publish Package Github +### Publish Github + +```yml +env: + GitHubToken: ${{ secrets.GITHUB_TOKEN }} +``` + +### SignFile and SignPassword ```yml env: @@ -60,6 +67,41 @@ env: SignPassword: ${{ secrets.SIGN_PASSWORD }} ``` +`SignFile` could be a `file/url/Base64` to the certificate file. +`SignPassword` is the password to the certificate file. + +#### SignFile using `Azure Key Vault` + +To simplify the configuration to sign with `Azure Key Vault` using the same environment variables are used `SignFile` and `SignPassword`. + +```yml +env: + GitHubToken: ${{ secrets.GITHUB_TOKEN }} + SignFile: ${{ secrets.SIGN_FILE_AZURE }} + SignPassword: ${{ secrets.SIGN_PASSWORD_AZURE }} +``` + +##### SIGN_FILE_AZURE + +The `SIGN_FILE_AZURE` is a `json` with the base configuration of the certificated in the `Azure Key Vault`: + +```json +{ + "AzureKeyVaultCertificate": "AzureKeyVaultCertificate", + "AzureKeyVaultUrl": "AzureKeyVaultUrl", + "AzureKeyVaultClientId": "AzureKeyVaultClientId", + "AzureKeyVaultTenantId": "AzureKeyVaultTenantId", + "TimestampUrl" : "http://timestamp.digicert.com" + "TimestampDigest" : "sha256" +} +``` + +The `TimestampUrl` and `TimestampDigest` are optional. + +##### SIGN_PASSWORD_AZURE + +The `SIGN_PASSWORD_AZURE` is the `AzureKeyVaultClientSecret` of the `Azure Key Vault` certificate. + ### Publish Package Nuget ```yml diff --git a/ricaun.Nuke.Example.Tests/ricaun.Nuke.Example.Tests.csproj b/ricaun.Nuke.Example.Tests/ricaun.Nuke.Example.Tests.csproj index 544eff1..90fdb2a 100644 --- a/ricaun.Nuke.Example.Tests/ricaun.Nuke.Example.Tests.csproj +++ b/ricaun.Nuke.Example.Tests/ricaun.Nuke.Example.Tests.csproj @@ -14,7 +14,7 @@ - net7.0 + net8.0 diff --git a/ricaun.Nuke.RevitAddin.Example/Properties/Resource.Designer.cs b/ricaun.Nuke.RevitAddin.Example/Properties/Resource.Designer.cs new file mode 100644 index 0000000..dce1317 --- /dev/null +++ b/ricaun.Nuke.RevitAddin.Example/Properties/Resource.Designer.cs @@ -0,0 +1,72 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace ricaun.Nuke.RevitAddin.Example.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resource { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resource() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ricaun.Nuke.RevitAddin.Example.Properties.Resource", typeof(Resource).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Text. + /// + internal static string Text { + get { + return ResourceManager.GetString("Text", resourceCulture); + } + } + } +} diff --git a/ricaun.Nuke.RevitAddin.Example/Properties/Resource.pt-BR.resx b/ricaun.Nuke.RevitAddin.Example/Properties/Resource.pt-BR.resx new file mode 100644 index 0000000..f7b59cd --- /dev/null +++ b/ricaun.Nuke.RevitAddin.Example/Properties/Resource.pt-BR.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Texto + + \ No newline at end of file diff --git a/ricaun.Nuke.RevitAddin.Example/Properties/Resource.resx b/ricaun.Nuke.RevitAddin.Example/Properties/Resource.resx new file mode 100644 index 0000000..8c9dc5f --- /dev/null +++ b/ricaun.Nuke.RevitAddin.Example/Properties/Resource.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Text + + \ No newline at end of file diff --git a/ricaun.Nuke.RevitAddin.Example/ricaun.Nuke.RevitAddin.Example.csproj b/ricaun.Nuke.RevitAddin.Example/ricaun.Nuke.RevitAddin.Example.csproj index 20d12a5..dd57f4a 100644 --- a/ricaun.Nuke.RevitAddin.Example/ricaun.Nuke.RevitAddin.Example.csproj +++ b/ricaun.Nuke.RevitAddin.Example/ricaun.Nuke.RevitAddin.Example.csproj @@ -124,4 +124,19 @@ + + + True + True + Resource.resx + + + + + + ResXFileCodeGenerator + Resource.Designer.cs + + + \ No newline at end of file diff --git a/ricaun.Nuke.Tests/AzureKeyVaultConfigTests.cs b/ricaun.Nuke.Tests/AzureKeyVaultConfigTests.cs new file mode 100644 index 0000000..fef486b --- /dev/null +++ b/ricaun.Nuke.Tests/AzureKeyVaultConfigTests.cs @@ -0,0 +1,56 @@ +using NUnit.Framework; +using ricaun.Nuke.Tools; + +namespace Nuke.NuGetKeyVaultSignTool +{ + public class AzureKeyVaultConfigTests + { + [Test] + public void JsonIsNotValidTest() + { + var content = """ + { + "AzureKeyVaultCertificate": "", + "AzureKeyVaultUrl": "", + "AzureKeyVaultClientId": "", + "AzureKeyVaultTenantId": "" + } + """; + + var azureKeyVaultFile = AzureKeyVaultConfig.Create(content); + Assert.IsNotNull(azureKeyVaultFile); + Assert.IsFalse(azureKeyVaultFile.IsValid()); + } + + [Test] + public void JsonIsNullTest() + { + var content = ""; + + var azureKeyVaultFile = AzureKeyVaultConfig.Create(content); + Assert.IsNull(azureKeyVaultFile); + } + + [Test] + public void JsonIsValidTest() + { + var content = """ + { + "AzureKeyVaultCertificate": "AzureKeyVaultCertificate", + "AzureKeyVaultUrl": "AzureKeyVaultUrl", + "AzureKeyVaultClientId": "AzureKeyVaultClientId", + "AzureKeyVaultTenantId": "AzureKeyVaultTenantId" + } + """; + + var azureKeyVaultFile = AzureKeyVaultConfig.Create(content); + Assert.IsNotNull(azureKeyVaultFile); + Assert.IsTrue(azureKeyVaultFile.IsValid()); + Assert.AreEqual("AzureKeyVaultCertificate", azureKeyVaultFile.AzureKeyVaultCertificate); + Assert.AreEqual("AzureKeyVaultUrl", azureKeyVaultFile.AzureKeyVaultUrl); + Assert.AreEqual("AzureKeyVaultClientId", azureKeyVaultFile.AzureKeyVaultClientId); + Assert.AreEqual("AzureKeyVaultTenantId", azureKeyVaultFile.AzureKeyVaultTenantId); + } + } + +} \ No newline at end of file diff --git a/ricaun.Nuke.Tests/TestsNet.cs b/ricaun.Nuke.Tests/NuGetExtensionTests.cs similarity index 90% rename from ricaun.Nuke.Tests/TestsNet.cs rename to ricaun.Nuke.Tests/NuGetExtensionTests.cs index 699414c..f50c629 100644 --- a/ricaun.Nuke.Tests/TestsNet.cs +++ b/ricaun.Nuke.Tests/NuGetExtensionTests.cs @@ -2,11 +2,10 @@ namespace ricaun.Nuke.Tests { -#if NET - public class TestsNet + public class NuGetExtensionTests { [Test] - public void Test1() + public void Test_PackageNameAndVersion() { var packages = new[] { "ricaun.example.1.2.3.nupkg", @@ -26,5 +25,4 @@ public void Test1() } } } -#endif } \ No newline at end of file diff --git a/ricaun.Nuke.Tests/ricaun.Nuke.Tests.csproj b/ricaun.Nuke.Tests/ricaun.Nuke.Tests.csproj index 5c61cf9..7472eba 100644 --- a/ricaun.Nuke.Tests/ricaun.Nuke.Tests.csproj +++ b/ricaun.Nuke.Tests/ricaun.Nuke.Tests.csproj @@ -1,7 +1,7 @@  - net6;net45 + net6 Latest false @@ -12,7 +12,7 @@ - + diff --git a/ricaun.Nuke.sln b/ricaun.Nuke.sln index 82b75d5..3d618f3 100644 --- a/ricaun.Nuke.sln +++ b/ricaun.Nuke.sln @@ -10,6 +10,7 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution", "Solution", "{4EED1749-7A3F-47C6-8361-F4E45A143AFA}" ProjectSection(SolutionItems) = preProject CHANGELOG.md = CHANGELOG.md + Directory.Build.props = Directory.Build.props README.md = README.md EndProjectSection EndProject @@ -19,7 +20,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ricaun.Nuke.RevitAddin.Exam EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ricaun.Nuke.Example.Tests", "ricaun.Nuke.Example.Tests\ricaun.Nuke.Example.Tests.csproj", "{36867697-93A0-4F07-AA4D-78FD70985EDE}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ricaun.Nuke.Tests", "ricaun.Nuke.Tests\ricaun.Nuke.Tests.csproj", "{80F1FFD0-AB40-40BE-83E6-10E425F41B30}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ricaun.Nuke.Tests", "ricaun.Nuke.Tests\ricaun.Nuke.Tests.csproj", "{80F1FFD0-AB40-40BE-83E6-10E425F41B30}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/ricaun.Nuke/CommonExtension.cs b/ricaun.Nuke/CommonExtension.cs index 90efccb..87a170b 100644 --- a/ricaun.Nuke/CommonExtension.cs +++ b/ricaun.Nuke/CommonExtension.cs @@ -1,4 +1,6 @@ using Nuke.Common; +using Nuke.Common.Utilities; +using System.Linq; namespace ricaun.Nuke { @@ -13,7 +15,33 @@ public static class CommonExtension /// /// /// - public static T From(this T nukeBuild) where T : INukeBuild => (T)(object)nukeBuild; + public static T From(this T nukeBuild) where T : INukeBuild + { + ShowVersion(); + return (T)(object)nukeBuild; + } + + internal static void ShowVersion() + { + Information(); + var assemblyName = typeof(CommonExtension).Assembly.GetName().Name; + foreach (var item in System.AppDomain.CurrentDomain.GetAssemblies() + .Where(e => e.GetName().Name.StartsWith(assemblyName, System.StringComparison.InvariantCultureIgnoreCase))) + { + Information($"{item.GetName().Name} {item.GetVersionText()}"); + } + } + + internal static void Information(string text = null) + { + try + { + // internal static void Information(string text = null) + typeof(Host).GetMethod("Information",System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static) + .Invoke(null, new object[] { text }); + } + catch { }; + } } } diff --git a/ricaun.Nuke/Components/IAssetRelease.cs b/ricaun.Nuke/Components/IAssetRelease.cs new file mode 100644 index 0000000..bb09f3d --- /dev/null +++ b/ricaun.Nuke/Components/IAssetRelease.cs @@ -0,0 +1,80 @@ +using Nuke.Common; +using Nuke.Common.IO; +using Nuke.Common.ProjectModel; +using ricaun.Nuke.IO; + +namespace ricaun.Nuke.Components +{ + /// + /// Represents the assets to be released. + /// + public class ReleaseAssets + { + /// + /// Gets the project associated with the release. + /// + public Project Project { get; init; } + + /// + /// Gets the version of the release. + /// + public string Version { get; init; } + + /// + /// Gets the release notes. + /// + public string Notes { get; init; } + + /// + /// Gets the collection of zip files to be released. + /// + public AbsolutePath[] Assets { get; init; } = new AbsolutePath[] { }; + + /// + /// Gets a value indicating whether the release is a prerelease. + /// + public bool Prerelease { get; init; } = false; + } + /// + /// Defines a component that has asset release capabilities + /// + /// executes inside and before release. + public interface IHazAssetRelease + { + /// + /// Gets the asset release instance. + /// + IAssetRelease AssetRelease => null; + + /// + /// Releases the specified assets. + /// + /// The assets to be released. + public void ExecuteReleaseAsset(ReleaseAssets releaseAssets) + { + if (AssetRelease is IAssetRelease assetRelease) + { + Serilog.Log.Information($"ReleaseAsset: {assetRelease}"); + assetRelease.ReleaseAsset(releaseAssets); + } + if (this is IAssetRelease buildAssetRelease) + { + Serilog.Log.Information($"ReleaseAsset: {buildAssetRelease}"); + buildAssetRelease.ReleaseAsset(releaseAssets); + } + } + } + + /// + /// Defines the interface for releasing assets. + /// + public interface IAssetRelease + { + /// + /// Releases the specified assets. + /// + /// The assets to be released. + /// Use to post/put the release files in a private server. + public void ReleaseAsset(ReleaseAssets releaseAssets); + } +} diff --git a/ricaun.Nuke/Components/IClean.cs b/ricaun.Nuke/Components/IClean.cs index 1e4b3bd..10d32c1 100644 --- a/ricaun.Nuke/Components/IClean.cs +++ b/ricaun.Nuke/Components/IClean.cs @@ -17,4 +17,4 @@ public interface IClean : IHazSolution, INukeBuild Solution.ClearSolution(BuildProjectDirectory); }); } -} +} \ No newline at end of file diff --git a/ricaun.Nuke/Components/IGitPreRelease.cs b/ricaun.Nuke/Components/IGitPreRelease.cs index f62db90..bd6d1fc 100644 --- a/ricaun.Nuke/Components/IGitPreRelease.cs +++ b/ricaun.Nuke/Components/IGitPreRelease.cs @@ -38,6 +38,7 @@ public bool HasPreReleaseFilter(string version) .OnlyWhenStatic(() => GitHubToken.SkipEmpty()) .OnlyWhenStatic(() => IsServerBuild) .OnlyWhenDynamic(() => GitRepository.IsOnDevelopBranch()) + .OnlyWhenDynamic(() => SkipForked()) .Executes(() => { var project = MainProject; @@ -54,7 +55,7 @@ public bool HasPreReleaseFilter(string version) return; } ReportSummary(_ => _.AddPair("Prerelease", version)); - ReleaseGithubProject(MainProject, true); + ReleaseGitHubProject(MainProject, true); }); } } diff --git a/ricaun.Nuke/Components/IGitRelease.cs b/ricaun.Nuke/Components/IGitRelease.cs index b6911a3..760158d 100644 --- a/ricaun.Nuke/Components/IGitRelease.cs +++ b/ricaun.Nuke/Components/IGitRelease.cs @@ -7,13 +7,14 @@ using ricaun.Nuke.Extensions; using System; using System.IO; +using System.Linq; namespace ricaun.Nuke.Components { /// /// IGitRelease /// - public interface IGitRelease : IRelease, IHazGitRepository, IHazGitVersion, IHazChangelog, INukeBuild + public interface IGitRelease : IRelease, IHazGitRepository, IHazGitVersion, IHazChangelog, IHazAssetRelease, INukeBuild { /// /// Target GitRelease @@ -25,6 +26,7 @@ public interface IGitRelease : IRelease, IHazGitRepository, IHazGitVersion, IHaz .OnlyWhenStatic(() => GitHubToken.SkipEmpty()) .OnlyWhenStatic(() => IsServerBuild) .OnlyWhenDynamic(() => GitRepository.IsOnMainOrMasterBranch()) + .OnlyWhenDynamic(() => SkipForked()) .Executes(() => { var project = MainProject; @@ -37,15 +39,15 @@ public interface IGitRelease : IRelease, IHazGitRepository, IHazGitVersion, IHaz throw new Exception(errorMessage); } - ReleaseGithubProject(project); + ReleaseGitHubProject(project); }); /// - /// Release Github project with release notes + /// Release GitHub project with release notes /// /// /// - void ReleaseGithubProject(Project project, bool releaseAsPrerelease = false) + void ReleaseGitHubProject(Project project, bool releaseAsPrerelease = false) { if (Directory.Exists(ReleaseDirectory) == false) { @@ -74,10 +76,22 @@ void ReleaseGithubProject(Project project, bool releaseAsPrerelease = false) return; } + var releaseNotes = GetReleaseNotes(); + var releaseAssets = new ReleaseAssets + { + Project = project, + Version = version, + Notes = releaseNotes, + Assets = releaseFiles.ToArray(), + Prerelease = releaseAsPrerelease + }; + + ExecuteReleaseAsset(releaseAssets); + var newRelease = new Octokit.NewRelease(version) { Name = version, - Body = GetReleaseNotes(), + Body = releaseNotes, Draft = true, TargetCommitish = GitVersion.Sha }; diff --git a/ricaun.Nuke/Components/IHazGitRepository.cs b/ricaun.Nuke/Components/IHazGitRepository.cs index dfc25a0..85572f9 100644 --- a/ricaun.Nuke/Components/IHazGitRepository.cs +++ b/ricaun.Nuke/Components/IHazGitRepository.cs @@ -1,45 +1,75 @@ -using Nuke.Common; -using Nuke.Common.Git; - -namespace ricaun.Nuke.Components -{ - /// - /// IHazGitRepository - /// - public interface IHazGitRepository : INukeBuild - { - /// - /// GitHubToken - /// - [Secret][Parameter] public string GitHubToken => TryGetValue(() => GitHubToken); - - /// - /// GitRepository - /// - [GitRepository] GitRepository GitRepository => TryGetValue(() => GitRepository); - - /// - /// GetGitRepositoryPackageUrl (default: https://nuget.pkg.github.com/repository_owner/index.json) - /// - /// - public string GetGitRepositoryPackageUrl() - { - if (GitRepository == null) - { - Serilog.Log.Warning($"GitRepository not found."); - return ""; - } - return $@"https://nuget.pkg.github.com/{GetGitRepositoryOwner()}/index.json"; - } - - /// - /// GetGitRepositoryOwner based on the GitRepository.Identifier - /// - /// - public string GetGitRepositoryOwner() - { - if (GitRepository == null) return ""; - return GitRepository.Identifier?.Split("/")[0]; - } - } -} +using Nuke.Common; +using Nuke.Common.Git; +using ricaun.Nuke.Extensions; + +namespace ricaun.Nuke.Components +{ + /// + /// IHazGitRepository + /// + public interface IHazGitRepository : INukeBuild + { + /// + /// GitHubToken + /// + [Secret][Parameter] public string GitHubToken => TryGetValue(() => GitHubToken); + + /// + /// GitRepository + /// + [GitRepository] GitRepository GitRepository => TryGetValue(() => GitRepository); + + /// + /// GetGitRepositoryPackageUrl (default: https://nuget.pkg.github.com/repository_owner/index.json) + /// + /// + public string GetGitRepositoryPackageUrl() + { + if (GitRepository == null) + { + Serilog.Log.Warning($"GitRepository not found."); + return ""; + } + return $@"https://nuget.pkg.github.com/{GetGitRepositoryOwner()}/index.json"; + } + + /// + /// GetGitRepositoryOwner based on the GitRepository.Identifier + /// + /// + public string GetGitRepositoryOwner() + { + if (GitRepository == null) return ""; + return GitRepository.Identifier?.Split("/")[0]; + } + + /// + /// Indicates whether the forked repository is enabled. + /// + [Parameter] + bool EnableForkedRepository => TryGetValue(() => EnableForkedRepository) ?? false; + + /// + /// Determines if the forked repository should be skipped. + /// + /// False if the forked repository should be skipped; otherwise, true. + public bool SkipForked() + { + if (EnableForkedRepository) + return true; + + if (IsGitRepositoryForked()) + return false; + + return true; + } + /// + /// IsGitRepositoryForked + /// + /// + public bool IsGitRepositoryForked() + { + return GitRepository.IsForked(); + } + } +} diff --git a/ricaun.Nuke/Components/IHazSign.cs b/ricaun.Nuke/Components/IHazSign.cs index bc20d1a..ab11fb0 100644 --- a/ricaun.Nuke/Components/IHazSign.cs +++ b/ricaun.Nuke/Components/IHazSign.cs @@ -3,6 +3,8 @@ using Nuke.Common.ProjectModel; using Nuke.Common.Utilities.Collections; using ricaun.Nuke.Extensions; +using ricaun.Nuke.Tools; +using System; namespace ricaun.Nuke.Components { @@ -61,24 +63,44 @@ public bool SignFolder(string folder, string namePattern = "*", bool dllSign = t return false; } - var certPath = SignExtension.VerifySignFile(SignFile, BuildAssemblyDirectory); - var certPassword = SignPassword; + Action signFile = null; - SignExtension.CreateCerFile(certPath, certPassword, BuildAssemblyDirectory); + if (AzureKeyVaultConfig.Create(SignFile) is AzureKeyVaultConfig azureKeyVaultConfig) + { + var azureKeyVaultClientSecret = SignPassword; + void SignUsingAzureKeyVault(string file) + { + AzureSignToolUtils.Sign(file, azureKeyVaultConfig, azureKeyVaultClientSecret); + } + signFile = SignUsingAzureKeyVault; + } + else + { + var certPath = SignExtension.VerifySignFile(SignFile, BuildAssemblyDirectory); + var certPassword = SignPassword; + + SignExtension.CreateCerFile(certPath, certPassword, BuildAssemblyDirectory); + + void SignUsingCerFile(string file) + { + SignExtension.Sign(certPath, certPassword, file); + } + signFile = SignUsingCerFile; + } Serilog.Log.Information($"SignFolder [{namePattern}]: {folder}"); if (dllSign) Globbing.GlobFiles(folder, $"**/{namePattern}.dll") - .ForEach(file => SignExtension.SignBinary(certPath, certPassword, file)); + .ForEach(signFile); if (nupkgSign) Globbing.GlobFiles(folder, $"**/{namePattern}.nupkg") - .ForEach(file => SignExtension.SignNuGet(certPath, certPassword, file)); + .ForEach(signFile); if (exeSign) Globbing.GlobFiles(folder, $"**/{namePattern}.exe") - .ForEach(file => SignExtension.SignBinary(certPath, certPassword, file)); + .ForEach(signFile); return Globbing.GlobFiles(folder, $"**/{namePattern}").Count > 0; } diff --git a/ricaun.Nuke/Components/IPack.cs b/ricaun.Nuke/Components/IPack.cs index ba16b7c..f2ab5ba 100644 --- a/ricaun.Nuke/Components/IPack.cs +++ b/ricaun.Nuke/Components/IPack.cs @@ -29,6 +29,7 @@ public interface IPack : IHazPack, IGitRelease .OnlyWhenStatic(() => NugetApiKey.SkipEmpty()) .OnlyWhenStatic(() => IsServerBuild) .OnlyWhenDynamic(() => GitRepository.IsOnMainOrMasterBranch()) + .OnlyWhenDynamic(() => SkipForked()) .Executes(() => { var releaseDirectory = GetReleaseDirectory(MainProject); diff --git a/ricaun.Nuke/Components/IPrePack.cs b/ricaun.Nuke/Components/IPrePack.cs index 84e2e78..a7b9718 100644 --- a/ricaun.Nuke/Components/IPrePack.cs +++ b/ricaun.Nuke/Components/IPrePack.cs @@ -24,6 +24,7 @@ public interface IPrePack : IPack, IGitPreRelease .OnlyWhenStatic(() => NugetApiKey.SkipEmpty()) .OnlyWhenStatic(() => IsServerBuild) .OnlyWhenDynamic(() => GitRepository.IsOnDevelopBranch()) + .OnlyWhenDynamic(() => SkipForked()) .Executes(() => { var version = MainProject.GetInformationalVersion(); diff --git a/ricaun.Nuke/Extensions/GitHubExtension.cs b/ricaun.Nuke/Extensions/GitHubExtension.cs index a54c463..964da5c 100644 --- a/ricaun.Nuke/Extensions/GitHubExtension.cs +++ b/ricaun.Nuke/Extensions/GitHubExtension.cs @@ -1,4 +1,5 @@ using Nuke.Common; +using Nuke.Common.Git; using Nuke.Common.IO; using Nuke.Common.Tools.GitHub; using Octokit; @@ -14,6 +15,35 @@ namespace ricaun.Nuke.Extensions /// public static class GitHubExtension { + /// + /// Determines whether the specified Git repository is a fork. + /// + /// The Git repository to check. + /// + /// true if the specified Git repository is a fork; otherwise, false. + /// + public static bool IsForked(this GitRepository gitRepository) + { + if (gitRepository is null) + return false; + + try + { + var gitHubOwner = gitRepository.GetGitHubOwner(); + var gitHubName = gitRepository.GetGitHubName(); + var repository = GitHubTasks.GitHubClient.Repository + .Get(gitHubOwner, gitHubName) + .Result; + + return repository.Fork; + } + catch + { + // Private repository is not forked. + return false; + } + } + #region GitHubUtil /// /// Check if Tags already exists. diff --git a/ricaun.Nuke/Extensions/NuGetExtension.cs b/ricaun.Nuke/Extensions/NuGetExtension.cs index dd3945e..3d40d82 100644 --- a/ricaun.Nuke/Extensions/NuGetExtension.cs +++ b/ricaun.Nuke/Extensions/NuGetExtension.cs @@ -46,6 +46,21 @@ public static NugetVersionInfo Parse(string packageFileName) /// public static class NuGetExtension { + /// + /// NuGetFileExtension (.nupkg) + /// + public const string NuGetFileExtension = ".nupkg"; + + /// + /// Check if file has NuGet extension (.nupkg) + /// + /// + /// + public static bool IsNuGetFile(string filePath) + { + return Path.GetExtension(filePath).Equals(NuGetFileExtension, StringComparison.InvariantCultureIgnoreCase); + } + /// /// TryGetPackageNameAndVersion /// diff --git a/ricaun.Nuke/Extensions/PathTooLongUtils.cs b/ricaun.Nuke/Extensions/PathTooLongUtils.cs index 7942c76..828f5a4 100644 --- a/ricaun.Nuke/Extensions/PathTooLongUtils.cs +++ b/ricaun.Nuke/Extensions/PathTooLongUtils.cs @@ -53,7 +53,7 @@ public int GetFilePathLong() /// public bool IsPathTooLong() { - return GetFilePathLong() > MAX_PATH; + return GetFilePathLong() >= MAX_PATH; } /// diff --git a/ricaun.Nuke/Extensions/SignExtension.cs b/ricaun.Nuke/Extensions/SignExtension.cs index b6e2221..32a650e 100644 --- a/ricaun.Nuke/Extensions/SignExtension.cs +++ b/ricaun.Nuke/Extensions/SignExtension.cs @@ -71,6 +71,24 @@ public static bool CreateCerFile(string fileNamePfx, string passwordPfx, string if (File.Exists(cert)) return true; return CreateCertificatesCer(fileNamePfx, passwordPfx, cert); } + + /// + /// Sign the specified file using the provided certificate. + /// + /// The path to the certificate file. + /// The password for the certificate. + /// The path to the file to be signed. + /// NuGet files use . + public static void Sign(string certPath, string certPassword, string filePath) + { + if (NuGetExtension.IsNuGetFile(filePath)) + { + SignNuGet(certPath, certPassword, filePath); + return; + } + SignBinary(certPath, certPassword, filePath); + } + /// /// https://github.com/DataDog/dd-trace-dotnet/blob/master/tracer/build/_build/Build.Gitlab.cs /// @@ -124,7 +142,7 @@ public static void SignBinary(string certPath, string certPassword, string binar } /// - /// Sign Nuget + /// Sign NuGet /// /// /// @@ -149,20 +167,24 @@ public static void SignNuGet(string certPath, string certPassword, string binary } /// - /// Has Signature + /// Has Signature in the file or NuGet /// - /// + /// /// - static bool HasSignature(string fileInfo) + public static bool HasSignature(string filePath) { - if (fileInfo.EndsWith(".nupkg")) + if (NuGetExtension.IsNuGetFile(filePath)) { - return NuGetExtension.NuGetVerifySignatures(fileInfo); + return NuGetExtension.NuGetVerifySignatures(filePath); } try { - System.Security.Cryptography.X509Certificates.X509Certificate.CreateFromSignedFile(fileInfo); + using (var utils = new PathTooLongUtils.FileMoveToTemp(filePath)) + { + filePath = utils.GetFilePath(); + System.Security.Cryptography.X509Certificates.X509Certificate.CreateFromSignedFile(filePath); + } return true; } catch diff --git a/ricaun.Nuke/IO/HttpAuthTasks.cs b/ricaun.Nuke/IO/HttpAuthTasks.cs new file mode 100644 index 0000000..39d2d41 --- /dev/null +++ b/ricaun.Nuke/IO/HttpAuthTasks.cs @@ -0,0 +1,599 @@ +using Nuke.Common; +using Nuke.Common.IO; +using Nuke.Common.Tooling; +using System; +using System.Collections.Generic; +using System.IO; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Threading.Tasks; + +namespace ricaun.Nuke.IO; + +/// +/// Provides a set of methods for performing HTTP requests with authentication. +/// +public static class HttpAuthTasks +{ + #region HttpPost + /// + /// Performs an asynchronous HTTP POST request with a file as the content. + /// + /// The URI to send the request to. + /// The path of the file to be sent as content. + /// The authorization token for the request. + /// The form data to be included in the request. + /// The name of the file stream content. + /// The configurator for the HttpClient. + /// The configurator for the HttpRequestHeaders. + /// The response content as a string. + public static async Task HttpPostFileAsync( + string uri, + string filePath, + string authorization = null, + Dictionary formData = null, + string fileStreamContentName = null, + Configure clientConfigurator = null, + Action headerConfigurator = null) + { + var content = CreateFormDataContent(filePath, formData, fileStreamContentName); + return await HttpPostAsync(uri, content, authorization, clientConfigurator, headerConfigurator); + } + + /// + /// Performs a synchronous HTTP POST request with a file as the content. + /// + /// The URI to send the request to. + /// The path of the file to be sent as content. + /// The authorization token for the request. + /// The form data to be included in the request. + /// The name of the file stream content. + /// The configurator for the HttpClient. + /// The configurator for the HttpRequestHeaders. + /// The response content as a string. + public static string HttpPostFile( + string uri, + string filePath, + string authorization = null, + Dictionary formData = null, + string fileStreamContentName = null, + Configure clientConfigurator = null, + Action headerConfigurator = null) + { + return HttpPostFileAsync(uri, filePath, authorization, formData, fileStreamContentName, clientConfigurator, headerConfigurator).GetAwaiter().GetResult(); + } + + /// + /// Performs an asynchronous HTTP POST request with a JSON object as the content. + /// + /// The URI to send the request to. + /// The JSON object to be sent as content. + /// The authorization token for the request. + /// The configurator for the HttpClient. + /// The configurator for the HttpRequestHeaders. + /// The response content as a string. + public static async Task HttpPostAsync( + string uri, + object content, + string authorization = null, + Configure clientConfigurator = null, + Action headerConfigurator = null) + { + return await HttpPostAsync(uri, JsonHttpContent(content), authorization, clientConfigurator, headerConfigurator); + } + + /// + /// Performs a synchronous HTTP POST request with a JSON object as the content. + /// + /// The URI to send the request to. + /// The JSON object to be sent as content. + /// The authorization token for the request. + /// The configurator for the HttpClient. + /// The configurator for the HttpRequestHeaders. + /// The response content as a string. + public static string HttpPost( + string uri, + object content, + string authorization = null, + Configure clientConfigurator = null, + Action headerConfigurator = null) + { + return HttpPostAsync(uri, content, authorization, clientConfigurator, headerConfigurator).GetAwaiter().GetResult(); + } + + /// + /// Performs an asynchronous HTTP POST request with a custom HttpContent object as the content. + /// + /// The URI to send the request to. + /// The custom HttpContent object to be sent as content. + /// The authorization token for the request. + /// The configurator for the HttpClient. + /// The configurator for the HttpRequestHeaders. + /// The response content as a string. + public static async Task HttpPostAsync( + string uri, + HttpContent httpContent = null, + string authorization = null, + Configure clientConfigurator = null, + Action headerConfigurator = null) + { + var httpClient = CreateHttpClient(authorization, clientConfigurator, headerConfigurator); + return await httpClient.PostAsync(uri, httpContent).Result.Content.ReadAsStringAsync(); + } + + /// + /// Performs a synchronous HTTP POST request with a custom HttpContent object as the content. + /// + /// The URI to send the request to. + /// The custom HttpContent object to be sent as content. + /// The authorization token for the request. + /// The configurator for the HttpClient. + /// The configurator for the HttpRequestHeaders. + /// The response content as a string. + public static string HttpPost( + string uri, + HttpContent httpContent = null, + string authorization = null, + Configure clientConfigurator = null, + Action headerConfigurator = null) + { + return HttpPostAsync(uri, httpContent, authorization, clientConfigurator, headerConfigurator).GetAwaiter().GetResult(); + } + #endregion + + #region HttpPut + /// + /// Sends an HTTP PUT request to the specified URI asynchronously and saves the response content to a file. + /// + /// The URI to which the request is sent. + /// The path of the file to be sent in the request. + /// The authorization header value. + /// The form data to be sent in the request. + /// The name of the file stream content. + /// A delegate to configure the . + /// A delegate to configure the request headers. + /// A task representing the asynchronous operation. The task result contains the response content as a string. + public static async Task HttpPutFileAsync( + string uri, + string filePath, + string authorization = null, + Dictionary formData = null, + string fileStreamContentName = null, + Configure clientConfigurator = null, + Action headerConfigurator = null) + { + var content = CreateFormDataContent(filePath, formData, fileStreamContentName); + return await HttpPostAsync(uri, content, authorization, clientConfigurator, headerConfigurator); + } + + /// + /// Sends an HTTP PUT request to the specified URI and saves the response content to a file. + /// + /// The URI to which the request is sent. + /// The path of the file to be sent in the request. + /// The authorization header value. + /// The form data to be sent in the request. + /// The name of the file stream content. + /// A delegate to configure the . + /// A delegate to configure the request headers. + /// The response content as a string. + public static string HttpPutFile( + string uri, + string filePath, + string authorization = null, + Dictionary formData = null, + string fileStreamContentName = null, + Configure clientConfigurator = null, + Action headerConfigurator = null) + { + return HttpPutFileAsync(uri, filePath, authorization, formData, fileStreamContentName, clientConfigurator, headerConfigurator).GetAwaiter().GetResult(); + } + + /// + /// Sends an HTTP PUT request to the specified URI asynchronously. + /// + /// The URI to which the request is sent. + /// The content to be sent in the request. + /// The authorization header value. + /// A delegate to configure the . + /// A delegate to configure the request headers. + /// A task representing the asynchronous operation. The task result contains the response content as a string. + public static async Task HttpPutAsync( + string uri, + object content, + string authorization = null, + Configure clientConfigurator = null, + Action headerConfigurator = null) + { + return await HttpPutAsync(uri, JsonHttpContent(content), authorization, clientConfigurator, headerConfigurator); + } + + /// + /// Sends an HTTP PUT request to the specified URI. + /// + /// The URI to which the request is sent. + /// The content to be sent in the request. + /// The authorization header value. + /// A delegate to configure the . + /// A delegate to configure the request headers. + /// The response content as a string. + public static string HttpPut( + string uri, + object content, + string authorization = null, + Configure clientConfigurator = null, + Action headerConfigurator = null) + { + return HttpPutAsync(uri, content, authorization, clientConfigurator, headerConfigurator).GetAwaiter().GetResult(); + } + /// + /// Sends an HTTP PUT request to the specified URI asynchronously. + /// + /// The URI to which the request is sent. + /// The HTTP content to send with the request. + /// The authorization header value. + /// A delegate to configure the . + /// A delegate to configure the request headers. + /// A task representing the asynchronous operation. The task result contains the response content as a string. + public static async Task HttpPutAsync( + string uri, + HttpContent httpContent = null, + string authorization = null, + Configure clientConfigurator = null, + Action headerConfigurator = null) + { + var httpClient = CreateHttpClient(authorization, clientConfigurator, headerConfigurator); + return await httpClient.PutAsync(uri, httpContent).Result.Content.ReadAsStringAsync(); + } + /// + /// Sends an HTTP PUT request to the specified URI and returns the response content as a string. + /// + /// The URI to which the request is sent. + /// The HTTP content to send with the request. + /// The authorization header value. + /// A delegate to configure the . + /// A delegate to configure the request headers. + /// The response content as a string. + public static string HttpPut( + string uri, + HttpContent httpContent = null, + string authorization = null, + Configure clientConfigurator = null, + Action headerConfigurator = null) + { + return HttpPutAsync(uri, httpContent, authorization, clientConfigurator, headerConfigurator).GetAwaiter().GetResult(); + } + #endregion + + #region HttpPatch + /// + /// Sends an HTTP PATCH request to the specified URI asynchronously and saves the response content to a file. + /// + /// The URI to which the request is sent. + /// The path of the file to be sent in the request. + /// The authorization header value. + /// The form data to be sent in the request. + /// The name of the file stream content. + /// A delegate to configure the . + /// A delegate to configure the request headers. + /// A task representing the asynchronous operation. The task result contains the response content as a string. + public static async Task HttpPatchFileAsync( + string uri, + string filePath, + string authorization = null, + Dictionary formData = null, + string fileStreamContentName = null, + Configure clientConfigurator = null, + Action headerConfigurator = null) + { + var content = CreateFormDataContent(filePath, formData, fileStreamContentName); + return await HttpPostAsync(uri, content, authorization, clientConfigurator, headerConfigurator); + } + + /// + /// Sends an HTTP PATCH request to the specified URI and saves the response content to a file. + /// + /// The URI to which the request is sent. + /// The path of the file to be sent in the request. + /// The authorization header value. + /// The form data to be sent in the request. + /// The name of the file stream content. + /// A delegate to configure the . + /// A delegate to configure the request headers. + /// The response content as a string. + public static string HttpPatchFile( + string uri, + string filePath, + string authorization = null, + Dictionary formData = null, + string fileStreamContentName = null, + Configure clientConfigurator = null, + Action headerConfigurator = null) + { + return HttpPatchFileAsync(uri, filePath, authorization, formData, fileStreamContentName, clientConfigurator, headerConfigurator).GetAwaiter().GetResult(); + } + + /// + /// Sends an HTTP PATCH request to the specified URI asynchronously. + /// + /// The URI to which the request is sent. + /// The content to be sent in the request. + /// The authorization header value. + /// A delegate to configure the . + /// A delegate to configure the request headers. + /// A task representing the asynchronous operation. The task result contains the response content as a string. + public static async Task HttpPatchAsync( + string uri, + object content, + string authorization = null, + Configure clientConfigurator = null, + Action headerConfigurator = null) + { + return await HttpPatchAsync(uri, JsonHttpContent(content), authorization, clientConfigurator, headerConfigurator); + } + + /// + /// Sends an HTTP PATCH request to the specified URI. + /// + /// The URI to which the request is sent. + /// The content to be sent in the request. + /// The authorization header value. + /// A delegate to configure the . + /// A delegate to configure the request headers. + /// The response content as a string. + public static string HttpPatch( + string uri, + object content, + string authorization = null, + Configure clientConfigurator = null, + Action headerConfigurator = null) + { + return HttpPatchAsync(uri, content, authorization, clientConfigurator, headerConfigurator).GetAwaiter().GetResult(); + } + + /// + /// Sends an HTTP PATCH request to the specified URI asynchronously. + /// + /// The URI to which the request is sent. + /// The HTTP content to send with the request. + /// The authorization header value. + /// A delegate to configure the . + /// A delegate to configure the request headers. + /// A task representing the asynchronous operation. The task result contains the response content as a string. + public static async Task HttpPatchAsync( + string uri, + HttpContent httpContent = null, + string authorization = null, + Configure clientConfigurator = null, + Action headerConfigurator = null) + { + var httpClient = CreateHttpClient(authorization, clientConfigurator, headerConfigurator); + return await httpClient.PatchAsync(uri, httpContent).Result.Content.ReadAsStringAsync(); + } + /// + /// Sends an HTTP PATCH request to the specified URI and returns the response content as a string. + /// + /// The URI to which the request is sent. + /// The HTTP content to send with the request. + /// The authorization header value. + /// A delegate to configure the . + /// A delegate to configure the request headers. + /// The response content as a string. + public static string HttpPatch( + string uri, + HttpContent httpContent = null, + string authorization = null, + Configure clientConfigurator = null, + Action headerConfigurator = null) + { + return HttpPatchAsync(uri, httpContent, authorization, clientConfigurator, headerConfigurator).GetAwaiter().GetResult(); + } + #endregion + + #region HttpGet + /// + /// Sends an HTTP GET request to the specified URI and saves the response content to a file. + /// + /// The URI to which the request is sent. + /// The path where the response content will be saved. + /// The authorization header value. + /// The file mode used to create the file. + /// A delegate to configure the . + /// A delegate to configure the request headers. + public static void HttpGetFile( + string uri, + string path, + string authorization = null, + FileMode mode = FileMode.Create, + Configure clientConfigurator = null, + Action headerConfigurator = null) + { + HttpGetFileAsync(uri, path, authorization, mode, clientConfigurator, headerConfigurator).GetAwaiter().GetResult(); + } + /// + /// Sends an HTTP GET request to the specified URI asynchronously and saves the response content to a file. + /// + /// The URI to which the request is sent. + /// The path where the response content will be saved. + /// The authorization header value. + /// The file mode used to create the file. + /// A delegate to configure the . + /// A delegate to configure the request headers. + /// A task representing the asynchronous operation. + public static async Task HttpGetFileAsync( + string uri, + AbsolutePath path, + string authorization = null, + FileMode mode = FileMode.Create, + Configure clientConfigurator = null, + Action headerConfigurator = null) + { + var httpClient = CreateHttpClient(authorization, clientConfigurator, headerConfigurator); + var response = await httpClient.GetAsync(uri); + Assert.True(response.IsSuccessStatusCode, $"{response.ReasonPhrase}: {uri}"); + + path.Parent.CreateDirectory(); + await using var fileStream = File.Open(path, mode); + await response.Content.CopyToAsync(fileStream); + } + /// + /// Sends an HTTP GET request to the specified URI asynchronously and returns the response content as a string. + /// + /// The URI to which the request is sent. + /// The authorization header value. + /// A delegate to configure the . + /// A delegate to configure the request headers. + /// A task representing the asynchronous operation. The task result contains the response content as a string. + public static async Task HttpGetAsync( + string uri, + string authorization = null, + Configure clientConfigurator = null, + Action headerConfigurator = null) + { + var httpClient = CreateHttpClient(authorization, clientConfigurator, headerConfigurator); + return await httpClient.GetAsync(uri).Result.Content.ReadAsStringAsync(); + } + /// + /// Sends an HTTP GET request to the specified URI and returns the response content as a string. + /// + /// The URI to which the request is sent. + /// The authorization header value. + /// A delegate to configure the . + /// A delegate to configure the request headers. + /// The response content as a string. + public static string HttpGet( + string uri, + string authorization = null, + Configure clientConfigurator = null, + Action headerConfigurator = null) + { + return HttpGetAsync(uri, authorization, clientConfigurator, headerConfigurator).GetAwaiter().GetResult(); + } + #endregion + + #region HttpDelete + /// + /// Sends an HTTP DELETE request to the specified URI and returns the response content as a string asynchronously. + /// + /// The URI to which the request is sent. + /// The authorization header value. + /// A delegate to configure the . + /// A delegate to configure the request headers. + /// A task representing the asynchronous operation. The task result contains the response content as a string. + public static async Task HttpDeleteAsync( + string uri, + string authorization = null, + Configure clientConfigurator = null, + Action headerConfigurator = null) + { + var httpClient = CreateHttpClient(authorization, clientConfigurator, headerConfigurator); + return await httpClient.DeleteAsync(uri).Result.Content.ReadAsStringAsync(); + } + /// + /// Sends an HTTP DELETE request to the specified URI and returns the response content as a string. + /// + /// The URI to which the request is sent. + /// The authorization header value. + /// A delegate to configure the . + /// A delegate to configure the request headers. + /// The response content as a string. + public static string HttpDelete( + string uri, + string authorization = null, + Configure clientConfigurator = null, + Action headerConfigurator = null) + { + return HttpDeleteAsync(uri, authorization, clientConfigurator, headerConfigurator).GetAwaiter().GetResult(); + } + #endregion + + #region HttpClient + /// + /// DefaultTimeout (30 seconds) + /// + public static TimeSpan DefaultTimeout = TimeSpan.FromSeconds(30); + + private static HttpClient CreateHttpClient( + string authorization = null, + Configure clientConfigurator = null, + Action headerConfigurator = null) + { + var httpClient = new HttpClient { Timeout = DefaultTimeout }; + SetBearerAuthorization(httpClient, authorization); + clientConfigurator?.Invoke(httpClient); + headerConfigurator?.Invoke(httpClient.DefaultRequestHeaders); + return httpClient; + } + private static void SetBearerAuthorization(HttpClient httpClient, string authorization = null) + { + const string HeaderAuthorization = "Authorization"; + if (!string.IsNullOrEmpty(authorization)) + { + httpClient.DefaultRequestHeaders.Add(HeaderAuthorization, $"Bearer {authorization}"); + } + } + + private static HttpContent JsonHttpContent(object content) + { + if (content is null) + content = string.Empty; + + HttpContent httpContent = null; + if (content is string stringContent) + { + httpContent = new StringContent(stringContent); + } + else if (content is HttpContent httpContentTo) + { + httpContent = httpContentTo; + } + else + { + const string MediaTypeJson = "application/json"; + httpContent = new StringContent(content.ToJson(), System.Text.Encoding.UTF8, MediaTypeJson); + } + + return httpContent; + } + + internal static MultipartFormDataContent CreateFormDataContent(string filePath, Dictionary formData = null, string fileStreamContentName = null) + { + if (!File.Exists(filePath)) + throw new FileNotFoundException("File not found.", filePath); + + var content = new MultipartFormDataContent(); + + if (formData is not null) + { + foreach (KeyValuePair vp in formData) + { + content.Add(new StringContent(vp.Value), vp.Key); + } + } + + if (string.IsNullOrEmpty(fileStreamContentName)) fileStreamContentName = "file"; + + var streamContent = new StreamContent(new FileStream(filePath, FileMode.Open)); + content.Add(streamContent, fileStreamContentName, Path.GetFileName(filePath)); + + return content; + } + #endregion + + #region Json + internal static string ToJson(this object obj) + { + if (obj is string t) + return t; + + return Newtonsoft.Json.JsonConvert.SerializeObject(obj); + } + internal static T FromJson(this string json) + { + if (json is T t) + return t; + + return Newtonsoft.Json.JsonConvert.DeserializeObject(json); + } + #endregion +} diff --git a/ricaun.Nuke/Tools/AzureSignToolUtils.cs b/ricaun.Nuke/Tools/AzureSignToolUtils.cs new file mode 100644 index 0000000..eeb8eb8 --- /dev/null +++ b/ricaun.Nuke/Tools/AzureSignToolUtils.cs @@ -0,0 +1,228 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ricaun.Nuke.Tools.NuGetKeyVaultSignTool; +using Nuke.Common.Tools.AzureSignTool; +using System.IO; +using Nuke.Common.Tools.DotNet; +using Nuke.Common.IO; +using Nuke.Common.Tooling; +using ricaun.Nuke.Extensions; + +namespace ricaun.Nuke.Tools +{ + /// + /// Utility class for working with Azure Sign Tool. + /// + public class AzureSignToolUtils + { + private const string TimestampUrlDefault = "http://timestamp.digicert.com"; + private const string TimestampDigestDefault = "sha256"; + + /// + /// Ensures that Azure Sign Tool and NuGet Key Vault Sign Tool are installed. + /// + /// Thrown when the required packages are missing. + public static void EnsureAzureToolIsInstalled() + { + DownloadAzureSignTool(); + DownloadNuGetKeyVaultSignTool(); + + try + { + _ = AzureSignToolTasks.AzureSignToolPath; + _ = NuGetKeyVaultSignToolTasks.NuGetKeyVaultSignToolPath; + } + catch (Exception ex) + { + var packagesToInstall = """ + + + + + """; + throw new Exception($"Missing package reference/download, install the packages in the project: \n{packagesToInstall}", ex); + } + } + + private static AbsolutePath GetToolInstallationPath() + { + var assemblyName = typeof(AzureSignToolUtils).Assembly.GetName(); + AbsolutePath folder = (AbsolutePath) Path.GetTempPath() / assemblyName.Name / assemblyName.Version.ToString(3); + return folder / "Tools"; + } + + private static string PackageDownload(string packageId) + { + var toolFolder = GetToolInstallationPath(); + + if (Globbing.GlobFiles(toolFolder, $"{packageId}.exe").FirstOrDefault() is AbsolutePath packageToolExeExists) + { + return packageToolExeExists; + } + + DotNetTasks.DotNetToolInstall(x => x + .SetPackageName(packageId) + .SetToolInstallationPath(toolFolder) + ); + + if (Globbing.GlobFiles(toolFolder, $"{packageId}.exe").FirstOrDefault() is AbsolutePath packageToolExe) + { + return packageToolExe; + } + return null; + } + + /// + /// Download AzureSignTool if not already installed. + /// + public static void DownloadAzureSignTool() + { + var packageId = AzureSignToolTasks.AzureSignToolPackageId; + var packageIdExe = packageId.ToUpper() + "_EXE"; + + if (ToolPathResolver.TryGetEnvironmentExecutable(packageIdExe) is null) + { + var packageToolExe = PackageDownload(packageId); + Environment.SetEnvironmentVariable(packageIdExe, packageToolExe); + } + + _ = AzureSignToolTasks.AzureSignToolPath; + } + + /// + /// Download NuGetKeyVaultSignTool if not already installed. + /// + public static void DownloadNuGetKeyVaultSignTool() + { + var packageId = NuGetKeyVaultSignToolTasks.NuGetKeyVaultSignToolPackageId; + var packageIdExe = packageId.ToUpper() + "_EXE"; + + if (ToolPathResolver.TryGetEnvironmentExecutable(packageIdExe) is null) + { + var packageToolExe = PackageDownload(packageId); + Environment.SetEnvironmentVariable(packageIdExe, packageToolExe); + } + + _ = NuGetKeyVaultSignToolTasks.NuGetKeyVaultSignToolPath; + } + + /// + /// Signs the specified file using Azure Sign Tool or NuGet Key Vault Sign Tool. + /// + /// The name of the file to sign. + /// The Azure Key Vault configuration. + /// The Azure Key Vault client secret. + /// The default timestamp URL. + /// The default timestamp digest. + public static void Sign(string filePath, + AzureKeyVaultConfig azureKeyVaultConfig, string azureKeyVaultClientSecret, + string timestampUrlDefault = TimestampUrlDefault, + string timestampDigestDefault = TimestampDigestDefault) + { + try + { + if (SignExtension.HasSignature(filePath)) + return; + + if (NuGetExtension.IsNuGetFile(filePath)) + { + DownloadNuGetKeyVaultSignTool(); + NuGetKeyVaultSignToolTasks.NuGetKeyVaultSignTool(x => x + .SetFile(filePath) + .SetKeyVaultCertificateName(azureKeyVaultConfig.AzureKeyVaultCertificate) + .SetKeyVaultUrl(azureKeyVaultConfig.AzureKeyVaultUrl) + .SetKeyVaultClientId(azureKeyVaultConfig.AzureKeyVaultClientId) + .SetKeyVaultTenantId(azureKeyVaultConfig.AzureKeyVaultTenantId) + .SetKeyVaultClientSecret(azureKeyVaultClientSecret) + .SetTimestampRfc3161Url(azureKeyVaultConfig.TimestampUrl ?? timestampUrlDefault) + .SetTimestampDigest(azureKeyVaultConfig.TimestampDigest ?? timestampDigestDefault) + ); + return; + } + + DownloadAzureSignTool(); + AzureSignToolTasks.AzureSignTool(x => x + .SetFiles(filePath) + .SetKeyVaultCertificateName(azureKeyVaultConfig.AzureKeyVaultCertificate) + .SetKeyVaultUrl(azureKeyVaultConfig.AzureKeyVaultUrl) + .SetKeyVaultClientId(azureKeyVaultConfig.AzureKeyVaultClientId) + .SetKeyVaultTenantId(azureKeyVaultConfig.AzureKeyVaultTenantId) + .SetKeyVaultClientSecret(azureKeyVaultClientSecret) + .SetTimestampRfc3161Url(azureKeyVaultConfig.TimestampUrl ?? timestampUrlDefault) + .SetTimestampDigest(azureKeyVaultConfig.TimestampDigest ?? timestampDigestDefault) + ); + } + catch (Exception ex) + { + Serilog.Log.Error($"Azure Sign Error: {Path.GetFileName(filePath)} - {ex.Message}"); + Serilog.Log.Information(ex.ToString()); + } + } + } + + /// + /// Represents the configuration for Azure Key Vault. + /// + public class AzureKeyVaultConfig + { + /// + /// Gets or sets the Azure Key Vault certificate. + /// + public string AzureKeyVaultCertificate { get; set; } + + /// + /// Gets or sets the Azure Key Vault URL. + /// + public string AzureKeyVaultUrl { get; set; } + + /// + /// Gets or sets the Azure Key Vault client ID. + /// + public string AzureKeyVaultClientId { get; set; } + + /// + /// Gets or sets the Azure Key Vault tenant ID. + /// + public string AzureKeyVaultTenantId { get; set; } + + /// + /// Gets or sets the timestamp URL. + /// + public string TimestampUrl { get; set; } + + /// + /// Gets or sets the timestamp digest. + /// + public string TimestampDigest { get; set; } + + /// + /// Creates an instance of from the specified JSON content. + /// + /// The JSON content representing the Azure Key Vault configuration. + /// An instance of . + public static AzureKeyVaultConfig Create(string jsonContent) + { + try + { + return Newtonsoft.Json.JsonConvert.DeserializeObject(jsonContent); + } + catch { } + return default; + } + + /// + /// Checks if the Azure Key Vault configuration is valid. + /// + /// true if the configuration is valid; otherwise, false. + public bool IsValid() + { + return !string.IsNullOrEmpty(AzureKeyVaultCertificate) && + !string.IsNullOrEmpty(AzureKeyVaultUrl) && + !string.IsNullOrEmpty(AzureKeyVaultClientId) && + !string.IsNullOrEmpty(AzureKeyVaultTenantId); + } + } +} diff --git a/ricaun.Nuke/Tools/NuGetKeyVaultSignTool/NuGetKeyVaultSignTool.Generated.cs b/ricaun.Nuke/Tools/NuGetKeyVaultSignTool/NuGetKeyVaultSignTool.Generated.cs new file mode 100644 index 0000000..5606c6f --- /dev/null +++ b/ricaun.Nuke/Tools/NuGetKeyVaultSignTool/NuGetKeyVaultSignTool.Generated.cs @@ -0,0 +1,661 @@ + +using JetBrains.Annotations; +using Newtonsoft.Json; +using Nuke.Common; +using Nuke.Common.Tooling; +using Nuke.Common.Tools; +using Nuke.Common.Utilities.Collections; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Linq; +using System.Text; + +namespace ricaun.Nuke.Tools.NuGetKeyVaultSignTool; + +/// +///

NuGet Key Vault Sign Tool is similar to nuget sign, with the major difference being that it uses Azure Key Vault for performing the signing process. Similar usage configuration like AzureSignTool, except is used to sign nuget package.

+///

For more details, visit the official website.

+///
+[PublicAPI] +[ExcludeFromCodeCoverage] +[NuGetPackageRequirement(NuGetKeyVaultSignToolPackageId)] +public partial class NuGetKeyVaultSignToolTasks + : IRequireNuGetPackage +{ + /// + /// NuGetKeyVaultSignToolPackageId + /// + public const string NuGetKeyVaultSignToolPackageId = "NuGetKeyVaultSignTool"; + /// + /// Path to the NuGetKeyVaultSignTool executable. + /// + public static string NuGetKeyVaultSignToolPath => + ToolPathResolver.TryGetEnvironmentExecutable("NUGETKEYVAULTSIGNTOOL_EXE") ?? + NuGetToolPathResolver.GetPackageExecutable("NuGetKeyVaultSignTool", "NuGetKeyVaultSignTool.dll"); + /// + /// NuGetKeyVaultSignToolLogger + /// + public static Action NuGetKeyVaultSignToolLogger { get; set; } = ProcessTasks.DefaultLogger; + /// + /// NuGetKeyVaultSignToolExitHandler + /// + public static Action NuGetKeyVaultSignToolExitHandler { get; set; } = ProcessTasks.DefaultExitHandler; + /// + ///

NuGet Key Vault Sign Tool is similar to nuget sign, with the major difference being that it uses Azure Key Vault for performing the signing process. Similar usage configuration like AzureSignTool, except is used to sign nuget package.

+ ///

For more details, visit the official website.

+ ///
+ public static IReadOnlyCollection NuGetKeyVaultSignTool(ArgumentStringHandler arguments, string workingDirectory = null, IReadOnlyDictionary environmentVariables = null, int? timeout = null, bool? logOutput = null, bool? logInvocation = null, Action logger = null, Action exitHandler = null) + { + using var process = ProcessTasks.StartProcess(NuGetKeyVaultSignToolPath, arguments, workingDirectory, environmentVariables, timeout, logOutput, logInvocation, logger ?? NuGetKeyVaultSignToolLogger); + (exitHandler ?? (p => NuGetKeyVaultSignToolExitHandler.Invoke(null, p))).Invoke(process.AssertWaitForExit()); + return process.Output; + } + /// + ///

NuGet Key Vault Sign Tool is similar to nuget sign, with the major difference being that it uses Azure Key Vault for performing the signing process. Similar usage configuration like AzureSignTool, except is used to sign nuget package.

+ ///

For more details, visit the official website.

+ ///
+ /// + ///

This is a CLI wrapper with fluent API that allows to modify the following arguments:

+ ///
    + ///
  • <file> via
  • + ///
  • --azure-key-vault-accesstoken via
  • + ///
  • --azure-key-vault-certificate via
  • + ///
  • --azure-key-vault-client-id via
  • + ///
  • --azure-key-vault-client-secret via
  • + ///
  • --azure-key-vault-managed-identity via
  • + ///
  • --azure-key-vault-tenant-id via
  • + ///
  • --azure-key-vault-url via
  • + ///
  • --file-digest via
  • + ///
  • --force via
  • + ///
  • --output via
  • + ///
  • --timestamp-digest via
  • + ///
  • --timestamp-rfc3161 via
  • + ///
+ ///
+ public static IReadOnlyCollection NuGetKeyVaultSignTool(NuGetKeyVaultSignToolSettings toolSettings = null) + { + toolSettings = toolSettings ?? new NuGetKeyVaultSignToolSettings(); + using var process = ProcessTasks.StartProcess(toolSettings); + toolSettings.ProcessExitHandler.Invoke(toolSettings, process.AssertWaitForExit()); + return process.Output; + } + /// + ///

NuGet Key Vault Sign Tool is similar to nuget sign, with the major difference being that it uses Azure Key Vault for performing the signing process. Similar usage configuration like AzureSignTool, except is used to sign nuget package.

+ ///

For more details, visit the official website.

+ ///
+ /// + ///

This is a CLI wrapper with fluent API that allows to modify the following arguments:

+ ///
    + ///
  • <file> via
  • + ///
  • --azure-key-vault-accesstoken via
  • + ///
  • --azure-key-vault-certificate via
  • + ///
  • --azure-key-vault-client-id via
  • + ///
  • --azure-key-vault-client-secret via
  • + ///
  • --azure-key-vault-managed-identity via
  • + ///
  • --azure-key-vault-tenant-id via
  • + ///
  • --azure-key-vault-url via
  • + ///
  • --file-digest via
  • + ///
  • --force via
  • + ///
  • --output via
  • + ///
  • --timestamp-digest via
  • + ///
  • --timestamp-rfc3161 via
  • + ///
+ ///
+ public static IReadOnlyCollection NuGetKeyVaultSignTool(Configure configurator) + { + return NuGetKeyVaultSignTool(configurator(new NuGetKeyVaultSignToolSettings())); + } + /// + ///

NuGet Key Vault Sign Tool is similar to nuget sign, with the major difference being that it uses Azure Key Vault for performing the signing process. Similar usage configuration like AzureSignTool, except is used to sign nuget package.

+ ///

For more details, visit the official website.

+ ///
+ /// + ///

This is a CLI wrapper with fluent API that allows to modify the following arguments:

+ ///
    + ///
  • <file> via
  • + ///
  • --azure-key-vault-accesstoken via
  • + ///
  • --azure-key-vault-certificate via
  • + ///
  • --azure-key-vault-client-id via
  • + ///
  • --azure-key-vault-client-secret via
  • + ///
  • --azure-key-vault-managed-identity via
  • + ///
  • --azure-key-vault-tenant-id via
  • + ///
  • --azure-key-vault-url via
  • + ///
  • --file-digest via
  • + ///
  • --force via
  • + ///
  • --output via
  • + ///
  • --timestamp-digest via
  • + ///
  • --timestamp-rfc3161 via
  • + ///
+ ///
+ public static IEnumerable<(NuGetKeyVaultSignToolSettings Settings, IReadOnlyCollection Output)> NuGetKeyVaultSignTool(CombinatorialConfigure configurator, int degreeOfParallelism = 1, bool completeOnFailure = false) + { + return configurator.Invoke(NuGetKeyVaultSignTool, NuGetKeyVaultSignToolLogger, degreeOfParallelism, completeOnFailure); + } +} +#region NuGetKeyVaultSignToolSettings +/// +/// Used within . +/// +[PublicAPI] +[ExcludeFromCodeCoverage] +[Serializable] +public partial class NuGetKeyVaultSignToolSettings : ToolSettings +{ + /// + /// Path to the NuGetKeyVaultSignTool executable. + /// + public override string ProcessToolPath => base.ProcessToolPath ?? NuGetKeyVaultSignToolTasks.NuGetKeyVaultSignToolPath; + /// + /// ProcessLogger + /// + public override Action ProcessLogger => base.ProcessLogger ?? NuGetKeyVaultSignToolTasks.NuGetKeyVaultSignToolLogger; + /// + /// ProcessExitHandler + /// + public override Action ProcessExitHandler => base.ProcessExitHandler ?? NuGetKeyVaultSignToolTasks.NuGetKeyVaultSignToolExitHandler; + /// + /// Package to sign. + /// + public virtual string File { get; internal set; } + /// + /// A fully qualified URL of the key vault with the certificate that will be used for signing. An example value might be https://my-vault.vault.azure.net. + /// + public virtual string KeyVaultUrl { get; internal set; } + /// + /// This is the client ID used to authenticate to Azure, which will be used to generate an access token. This parameter is not required if an access token is supplied directly with the --azure-key-vault-accesstoken option. If this parameter is supplied, --azure-key-vault-client-secret and --azure-key-vault-tenant-id must be supplied as well. + /// + public virtual string KeyVaultClientId { get; internal set; } + /// + /// This is the client secret used to authenticate to Azure, which will be used to generate an access token. This parameter is not required if an access token is supplied directly with the --azure-key-vault-accesstoken option or when using managed identities with --azure-key-vault-managed-identity. If this parameter is supplied, --azure-key-vault-client-id and --azure-key-vault-tenant-id must be supplied as well. + /// + public virtual string KeyVaultClientSecret { get; internal set; } + /// + /// This is the tenant id used to authenticate to Azure, which will be used to generate an access token. This parameter is not required if an access token is supplied directly with the --azure-key-vault-accesstoken option or when using managed identities with --azure-key-vault-managed-identity. If this parameter is supplied, --azure-key-vault-client-id and --azure-key-vault-client-secret must be supplied as well. + /// + public virtual string KeyVaultTenantId { get; internal set; } + /// + /// The name of the certificate used to perform the signing operation. + /// + public virtual string KeyVaultCertificateName { get; internal set; } + /// + /// An access token used to authenticate to Azure. This can be used instead of the --azure-key-vault-managed-identity, --azure-key-vault-client-id and --azure-key-vault-client-secret options. This is useful if NuGetKeyVaultSignTool is being used as part of another program that is already authenticated and has an access token to Azure. + /// + public virtual string KeyVaultAccessToken { get; internal set; } + /// + /// Use the ambient Managed Identity to authenticate to Azure. This can be used instead of the --azure-key-vault-accesstoken, --azure-key-vault-client-id and --azure-key-vault-client-secret options. This is useful if NuGetKeyVaultSignTool is being used on a VM/service/CLI that is configured for managed identities to Azure. + /// + public virtual bool? KeyVaultManagedIdentity { get; internal set; } + /// + /// A URL to an RFC3161 compliant timestamping service. This parameter serves the same purpose as the /tr option in the Windows SDK signtool. This parameter should be used in favor of the --timestamp option. Using this parameter will allow using modern, RFC3161 timestamps which also support timestamp digest algorithms other than SHA1. + /// + public virtual string TimestampRfc3161Url { get; internal set; } + /// + /// The name of the digest algorithm used for timestamping. This parameter is ignored unless the --timestamp-rfc3161 parameter is also supplied. The default value is sha256. + /// + public virtual NuGetKeyVaultSignToolDigestAlgorithm TimestampDigest { get; internal set; } + /// + /// The name of the digest algorithm used for hashing the file being signed. The default value is sha256. + /// + public virtual NuGetKeyVaultSignToolDigestAlgorithm FileDigest { get; internal set; } + /// + /// Overwrites a signature if it exists. + /// + public virtual bool? Force { get; internal set; } + /// + /// The output file. If omitted, overwrites input. + /// + public virtual string Output { get; internal set; } + /// + /// ConfigureProcessArguments + /// + /// + /// + protected override Arguments ConfigureProcessArguments(Arguments arguments) + { + arguments + .Add("sign") + .Add("{value}", File) + .Add("--azure-key-vault-url {value}", KeyVaultUrl) + .Add("--azure-key-vault-client-id {value}", KeyVaultClientId) + .Add("--azure-key-vault-client-secret {value}", KeyVaultClientSecret, secret: true) + .Add("--azure-key-vault-tenant-id {value}", KeyVaultTenantId) + .Add("--azure-key-vault-certificate {value}", KeyVaultCertificateName) + .Add("--azure-key-vault-accesstoken {value}", KeyVaultAccessToken, secret: true) + .Add("--azure-key-vault-managed-identity", KeyVaultManagedIdentity) + .Add("--timestamp-rfc3161 {value}", TimestampRfc3161Url) + .Add("--timestamp-digest {value}", TimestampDigest) + .Add("--file-digest {value}", FileDigest) + .Add("--force", Force) + .Add("--output {value}", Output); + return base.ConfigureProcessArguments(arguments); + } +} +#endregion +#region NuGetKeyVaultSignToolSettingsExtensions +/// +/// Used within . +/// +[PublicAPI] +[ExcludeFromCodeCoverage] +public static partial class NuGetKeyVaultSignToolSettingsExtensions +{ + #region File + /// + ///

Sets

+ ///

Package to sign.

+ ///
+ [Pure] + public static T SetFile(this T toolSettings, string file) where T : NuGetKeyVaultSignToolSettings + { + toolSettings = toolSettings.NewInstance(); + toolSettings.File = file; + return toolSettings; + } + /// + ///

Resets

+ ///

Package to sign.

+ ///
+ [Pure] + public static T ResetFile(this T toolSettings) where T : NuGetKeyVaultSignToolSettings + { + toolSettings = toolSettings.NewInstance(); + toolSettings.File = null; + return toolSettings; + } + #endregion + #region KeyVaultUrl + /// + ///

Sets

+ ///

A fully qualified URL of the key vault with the certificate that will be used for signing. An example value might be https://my-vault.vault.azure.net.

+ ///
+ [Pure] + public static T SetKeyVaultUrl(this T toolSettings, string keyVaultUrl) where T : NuGetKeyVaultSignToolSettings + { + toolSettings = toolSettings.NewInstance(); + toolSettings.KeyVaultUrl = keyVaultUrl; + return toolSettings; + } + /// + ///

Resets

+ ///

A fully qualified URL of the key vault with the certificate that will be used for signing. An example value might be https://my-vault.vault.azure.net.

+ ///
+ [Pure] + public static T ResetKeyVaultUrl(this T toolSettings) where T : NuGetKeyVaultSignToolSettings + { + toolSettings = toolSettings.NewInstance(); + toolSettings.KeyVaultUrl = null; + return toolSettings; + } + #endregion + #region KeyVaultClientId + /// + ///

Sets

+ ///

This is the client ID used to authenticate to Azure, which will be used to generate an access token. This parameter is not required if an access token is supplied directly with the --azure-key-vault-accesstoken option. If this parameter is supplied, --azure-key-vault-client-secret and --azure-key-vault-tenant-id must be supplied as well.

+ ///
+ [Pure] + public static T SetKeyVaultClientId(this T toolSettings, string keyVaultClientId) where T : NuGetKeyVaultSignToolSettings + { + toolSettings = toolSettings.NewInstance(); + toolSettings.KeyVaultClientId = keyVaultClientId; + return toolSettings; + } + /// + ///

Resets

+ ///

This is the client ID used to authenticate to Azure, which will be used to generate an access token. This parameter is not required if an access token is supplied directly with the --azure-key-vault-accesstoken option. If this parameter is supplied, --azure-key-vault-client-secret and --azure-key-vault-tenant-id must be supplied as well.

+ ///
+ [Pure] + public static T ResetKeyVaultClientId(this T toolSettings) where T : NuGetKeyVaultSignToolSettings + { + toolSettings = toolSettings.NewInstance(); + toolSettings.KeyVaultClientId = null; + return toolSettings; + } + #endregion + #region KeyVaultClientSecret + /// + ///

Sets

+ ///

This is the client secret used to authenticate to Azure, which will be used to generate an access token. This parameter is not required if an access token is supplied directly with the --azure-key-vault-accesstoken option or when using managed identities with --azure-key-vault-managed-identity. If this parameter is supplied, --azure-key-vault-client-id and --azure-key-vault-tenant-id must be supplied as well.

+ ///
+ [Pure] + public static T SetKeyVaultClientSecret(this T toolSettings, [Secret] string keyVaultClientSecret) where T : NuGetKeyVaultSignToolSettings + { + toolSettings = toolSettings.NewInstance(); + toolSettings.KeyVaultClientSecret = keyVaultClientSecret; + return toolSettings; + } + /// + ///

Resets

+ ///

This is the client secret used to authenticate to Azure, which will be used to generate an access token. This parameter is not required if an access token is supplied directly with the --azure-key-vault-accesstoken option or when using managed identities with --azure-key-vault-managed-identity. If this parameter is supplied, --azure-key-vault-client-id and --azure-key-vault-tenant-id must be supplied as well.

+ ///
+ [Pure] + public static T ResetKeyVaultClientSecret(this T toolSettings) where T : NuGetKeyVaultSignToolSettings + { + toolSettings = toolSettings.NewInstance(); + toolSettings.KeyVaultClientSecret = null; + return toolSettings; + } + #endregion + #region KeyVaultTenantId + /// + ///

Sets

+ ///

This is the tenant id used to authenticate to Azure, which will be used to generate an access token. This parameter is not required if an access token is supplied directly with the --azure-key-vault-accesstoken option or when using managed identities with --azure-key-vault-managed-identity. If this parameter is supplied, --azure-key-vault-client-id and --azure-key-vault-client-secret must be supplied as well.

+ ///
+ [Pure] + public static T SetKeyVaultTenantId(this T toolSettings, string keyVaultTenantId) where T : NuGetKeyVaultSignToolSettings + { + toolSettings = toolSettings.NewInstance(); + toolSettings.KeyVaultTenantId = keyVaultTenantId; + return toolSettings; + } + /// + ///

Resets

+ ///

This is the tenant id used to authenticate to Azure, which will be used to generate an access token. This parameter is not required if an access token is supplied directly with the --azure-key-vault-accesstoken option or when using managed identities with --azure-key-vault-managed-identity. If this parameter is supplied, --azure-key-vault-client-id and --azure-key-vault-client-secret must be supplied as well.

+ ///
+ [Pure] + public static T ResetKeyVaultTenantId(this T toolSettings) where T : NuGetKeyVaultSignToolSettings + { + toolSettings = toolSettings.NewInstance(); + toolSettings.KeyVaultTenantId = null; + return toolSettings; + } + #endregion + #region KeyVaultCertificateName + /// + ///

Sets

+ ///

The name of the certificate used to perform the signing operation.

+ ///
+ [Pure] + public static T SetKeyVaultCertificateName(this T toolSettings, string keyVaultCertificateName) where T : NuGetKeyVaultSignToolSettings + { + toolSettings = toolSettings.NewInstance(); + toolSettings.KeyVaultCertificateName = keyVaultCertificateName; + return toolSettings; + } + /// + ///

Resets

+ ///

The name of the certificate used to perform the signing operation.

+ ///
+ [Pure] + public static T ResetKeyVaultCertificateName(this T toolSettings) where T : NuGetKeyVaultSignToolSettings + { + toolSettings = toolSettings.NewInstance(); + toolSettings.KeyVaultCertificateName = null; + return toolSettings; + } + #endregion + #region KeyVaultAccessToken + /// + ///

Sets

+ ///

An access token used to authenticate to Azure. This can be used instead of the --azure-key-vault-managed-identity, --azure-key-vault-client-id and --azure-key-vault-client-secret options. This is useful if NuGetKeyVaultSignTool is being used as part of another program that is already authenticated and has an access token to Azure.

+ ///
+ [Pure] + public static T SetKeyVaultAccessToken(this T toolSettings, [Secret] string keyVaultAccessToken) where T : NuGetKeyVaultSignToolSettings + { + toolSettings = toolSettings.NewInstance(); + toolSettings.KeyVaultAccessToken = keyVaultAccessToken; + return toolSettings; + } + /// + ///

Resets

+ ///

An access token used to authenticate to Azure. This can be used instead of the --azure-key-vault-managed-identity, --azure-key-vault-client-id and --azure-key-vault-client-secret options. This is useful if NuGetKeyVaultSignTool is being used as part of another program that is already authenticated and has an access token to Azure.

+ ///
+ [Pure] + public static T ResetKeyVaultAccessToken(this T toolSettings) where T : NuGetKeyVaultSignToolSettings + { + toolSettings = toolSettings.NewInstance(); + toolSettings.KeyVaultAccessToken = null; + return toolSettings; + } + #endregion + #region KeyVaultManagedIdentity + /// + ///

Sets

+ ///

Use the ambient Managed Identity to authenticate to Azure. This can be used instead of the --azure-key-vault-accesstoken, --azure-key-vault-client-id and --azure-key-vault-client-secret options. This is useful if NuGetKeyVaultSignTool is being used on a VM/service/CLI that is configured for managed identities to Azure.

+ ///
+ [Pure] + public static T SetKeyVaultManagedIdentity(this T toolSettings, bool? keyVaultManagedIdentity) where T : NuGetKeyVaultSignToolSettings + { + toolSettings = toolSettings.NewInstance(); + toolSettings.KeyVaultManagedIdentity = keyVaultManagedIdentity; + return toolSettings; + } + /// + ///

Resets

+ ///

Use the ambient Managed Identity to authenticate to Azure. This can be used instead of the --azure-key-vault-accesstoken, --azure-key-vault-client-id and --azure-key-vault-client-secret options. This is useful if NuGetKeyVaultSignTool is being used on a VM/service/CLI that is configured for managed identities to Azure.

+ ///
+ [Pure] + public static T ResetKeyVaultManagedIdentity(this T toolSettings) where T : NuGetKeyVaultSignToolSettings + { + toolSettings = toolSettings.NewInstance(); + toolSettings.KeyVaultManagedIdentity = null; + return toolSettings; + } + /// + ///

Enables

+ ///

Use the ambient Managed Identity to authenticate to Azure. This can be used instead of the --azure-key-vault-accesstoken, --azure-key-vault-client-id and --azure-key-vault-client-secret options. This is useful if NuGetKeyVaultSignTool is being used on a VM/service/CLI that is configured for managed identities to Azure.

+ ///
+ [Pure] + public static T EnableKeyVaultManagedIdentity(this T toolSettings) where T : NuGetKeyVaultSignToolSettings + { + toolSettings = toolSettings.NewInstance(); + toolSettings.KeyVaultManagedIdentity = true; + return toolSettings; + } + /// + ///

Disables

+ ///

Use the ambient Managed Identity to authenticate to Azure. This can be used instead of the --azure-key-vault-accesstoken, --azure-key-vault-client-id and --azure-key-vault-client-secret options. This is useful if NuGetKeyVaultSignTool is being used on a VM/service/CLI that is configured for managed identities to Azure.

+ ///
+ [Pure] + public static T DisableKeyVaultManagedIdentity(this T toolSettings) where T : NuGetKeyVaultSignToolSettings + { + toolSettings = toolSettings.NewInstance(); + toolSettings.KeyVaultManagedIdentity = false; + return toolSettings; + } + /// + ///

Toggles

+ ///

Use the ambient Managed Identity to authenticate to Azure. This can be used instead of the --azure-key-vault-accesstoken, --azure-key-vault-client-id and --azure-key-vault-client-secret options. This is useful if NuGetKeyVaultSignTool is being used on a VM/service/CLI that is configured for managed identities to Azure.

+ ///
+ [Pure] + public static T ToggleKeyVaultManagedIdentity(this T toolSettings) where T : NuGetKeyVaultSignToolSettings + { + toolSettings = toolSettings.NewInstance(); + toolSettings.KeyVaultManagedIdentity = !toolSettings.KeyVaultManagedIdentity; + return toolSettings; + } + #endregion + #region TimestampRfc3161Url + /// + ///

Sets

+ ///

A URL to an RFC3161 compliant timestamping service. This parameter serves the same purpose as the /tr option in the Windows SDK signtool. This parameter should be used in favor of the --timestamp option. Using this parameter will allow using modern, RFC3161 timestamps which also support timestamp digest algorithms other than SHA1.

+ ///
+ [Pure] + public static T SetTimestampRfc3161Url(this T toolSettings, string timestampRfc3161Url) where T : NuGetKeyVaultSignToolSettings + { + toolSettings = toolSettings.NewInstance(); + toolSettings.TimestampRfc3161Url = timestampRfc3161Url; + return toolSettings; + } + /// + ///

Resets

+ ///

A URL to an RFC3161 compliant timestamping service. This parameter serves the same purpose as the /tr option in the Windows SDK signtool. This parameter should be used in favor of the --timestamp option. Using this parameter will allow using modern, RFC3161 timestamps which also support timestamp digest algorithms other than SHA1.

+ ///
+ [Pure] + public static T ResetTimestampRfc3161Url(this T toolSettings) where T : NuGetKeyVaultSignToolSettings + { + toolSettings = toolSettings.NewInstance(); + toolSettings.TimestampRfc3161Url = null; + return toolSettings; + } + #endregion + #region TimestampDigest + /// + ///

Sets

+ ///

The name of the digest algorithm used for timestamping. This parameter is ignored unless the --timestamp-rfc3161 parameter is also supplied. The default value is sha256.

+ ///
+ [Pure] + public static T SetTimestampDigest(this T toolSettings, NuGetKeyVaultSignToolDigestAlgorithm timestampDigest) where T : NuGetKeyVaultSignToolSettings + { + toolSettings = toolSettings.NewInstance(); + toolSettings.TimestampDigest = timestampDigest; + return toolSettings; + } + /// + ///

Resets

+ ///

The name of the digest algorithm used for timestamping. This parameter is ignored unless the --timestamp-rfc3161 parameter is also supplied. The default value is sha256.

+ ///
+ [Pure] + public static T ResetTimestampDigest(this T toolSettings) where T : NuGetKeyVaultSignToolSettings + { + toolSettings = toolSettings.NewInstance(); + toolSettings.TimestampDigest = null; + return toolSettings; + } + #endregion + #region FileDigest + /// + ///

Sets

+ ///

The name of the digest algorithm used for hashing the file being signed. The default value is sha256.

+ ///
+ [Pure] + public static T SetFileDigest(this T toolSettings, NuGetKeyVaultSignToolDigestAlgorithm fileDigest) where T : NuGetKeyVaultSignToolSettings + { + toolSettings = toolSettings.NewInstance(); + toolSettings.FileDigest = fileDigest; + return toolSettings; + } + /// + ///

Resets

+ ///

The name of the digest algorithm used for hashing the file being signed. The default value is sha256.

+ ///
+ [Pure] + public static T ResetFileDigest(this T toolSettings) where T : NuGetKeyVaultSignToolSettings + { + toolSettings = toolSettings.NewInstance(); + toolSettings.FileDigest = null; + return toolSettings; + } + #endregion + #region Force + /// + ///

Sets

+ ///

Overwrites a signature if it exists.

+ ///
+ [Pure] + public static T SetForce(this T toolSettings, bool? force) where T : NuGetKeyVaultSignToolSettings + { + toolSettings = toolSettings.NewInstance(); + toolSettings.Force = force; + return toolSettings; + } + /// + ///

Resets

+ ///

Overwrites a signature if it exists.

+ ///
+ [Pure] + public static T ResetForce(this T toolSettings) where T : NuGetKeyVaultSignToolSettings + { + toolSettings = toolSettings.NewInstance(); + toolSettings.Force = null; + return toolSettings; + } + /// + ///

Enables

+ ///

Overwrites a signature if it exists.

+ ///
+ [Pure] + public static T EnableForce(this T toolSettings) where T : NuGetKeyVaultSignToolSettings + { + toolSettings = toolSettings.NewInstance(); + toolSettings.Force = true; + return toolSettings; + } + /// + ///

Disables

+ ///

Overwrites a signature if it exists.

+ ///
+ [Pure] + public static T DisableForce(this T toolSettings) where T : NuGetKeyVaultSignToolSettings + { + toolSettings = toolSettings.NewInstance(); + toolSettings.Force = false; + return toolSettings; + } + /// + ///

Toggles

+ ///

Overwrites a signature if it exists.

+ ///
+ [Pure] + public static T ToggleForce(this T toolSettings) where T : NuGetKeyVaultSignToolSettings + { + toolSettings = toolSettings.NewInstance(); + toolSettings.Force = !toolSettings.Force; + return toolSettings; + } + #endregion + #region Output + /// + ///

Sets

+ ///

The output file. If omitted, overwrites input.

+ ///
+ [Pure] + public static T SetOutput(this T toolSettings, string output) where T : NuGetKeyVaultSignToolSettings + { + toolSettings = toolSettings.NewInstance(); + toolSettings.Output = output; + return toolSettings; + } + /// + ///

Resets

+ ///

The output file. If omitted, overwrites input.

+ ///
+ [Pure] + public static T ResetOutput(this T toolSettings) where T : NuGetKeyVaultSignToolSettings + { + toolSettings = toolSettings.NewInstance(); + toolSettings.Output = null; + return toolSettings; + } + #endregion +} +#endregion +#region NuGetKeyVaultSignToolDigestAlgorithm +/// +/// Used within . +/// +[PublicAPI] +[Serializable] +[ExcludeFromCodeCoverage] +[TypeConverter(typeof(TypeConverter))] +public partial class NuGetKeyVaultSignToolDigestAlgorithm : Enumeration +{ + /// + /// sha1 + /// + public static NuGetKeyVaultSignToolDigestAlgorithm sha1 = (NuGetKeyVaultSignToolDigestAlgorithm) "sha1"; + /// + /// sha256 + /// + public static NuGetKeyVaultSignToolDigestAlgorithm sha256 = (NuGetKeyVaultSignToolDigestAlgorithm) "sha256"; + /// + /// sha512 + /// + public static NuGetKeyVaultSignToolDigestAlgorithm sha384 = (NuGetKeyVaultSignToolDigestAlgorithm) "sha384"; + /// + /// sha512 + /// + public static NuGetKeyVaultSignToolDigestAlgorithm sha512 = (NuGetKeyVaultSignToolDigestAlgorithm) "sha512"; + /// + /// NuGetKeyVaultSignToolDigestAlgorithm + /// + /// + public static implicit operator NuGetKeyVaultSignToolDigestAlgorithm(string value) + { + return new NuGetKeyVaultSignToolDigestAlgorithm { Value = value }; + } +} +#endregion diff --git a/ricaun.Nuke/Tools/NuGetKeyVaultSignTool/NuGetKeyVaultSignTool.json b/ricaun.Nuke/Tools/NuGetKeyVaultSignTool/NuGetKeyVaultSignTool.json new file mode 100644 index 0000000..7ad5acd --- /dev/null +++ b/ricaun.Nuke/Tools/NuGetKeyVaultSignTool/NuGetKeyVaultSignTool.json @@ -0,0 +1,113 @@ +{ + "$schema": "https://raw.githubusercontent.com/nuke-build/nuke/master/source/Nuke.Tooling.Generator/schema.json", + "name": "NuGetKeyVaultSignTool", + "officialUrl": "https://github.com/novotnyllc/NuGetKeyVaultSignTool", + "help": "NuGet Key Vault Sign Tool is similar to nuget sign, with the major difference being that it uses Azure Key Vault for performing the signing process. Similar usage configuration like AzureSignTool, except is used to sign nuget package.", + "nugetPackageId": "NuGetKeyVaultSignTool", + "packageExecutable": "NuGetKeyVaultSignTool.dll", + "tasks": [ + { + "definiteArgument": "sign", + "settingsClass": { + "properties": [ + { + "name": "File", + "type": "string", + "format": "{value}", + "help": "Package to sign." + }, + { + "name": "KeyVaultUrl", + "type": "string", + "format": "--azure-key-vault-url {value}", + "secret": false, + "help": "A fully qualified URL of the key vault with the certificate that will be used for signing. An example value might be https://my-vault.vault.azure.net." + }, + { + "name": "KeyVaultClientId", + "type": "string", + "format": "--azure-key-vault-client-id {value}", + "secret": false, + "help": "This is the client ID used to authenticate to Azure, which will be used to generate an access token. This parameter is not required if an access token is supplied directly with the --azure-key-vault-accesstoken option. If this parameter is supplied, --azure-key-vault-client-secret and --azure-key-vault-tenant-id must be supplied as well." + }, + { + "name": "KeyVaultClientSecret", + "type": "string", + "format": "--azure-key-vault-client-secret {value}", + "secret": true, + "help": "This is the client secret used to authenticate to Azure, which will be used to generate an access token. This parameter is not required if an access token is supplied directly with the --azure-key-vault-accesstoken option or when using managed identities with --azure-key-vault-managed-identity. If this parameter is supplied, --azure-key-vault-client-id and --azure-key-vault-tenant-id must be supplied as well." + }, + { + "name": "KeyVaultTenantId", + "type": "string", + "format": "--azure-key-vault-tenant-id {value}", + "secret": false, + "help": "This is the tenant id used to authenticate to Azure, which will be used to generate an access token. This parameter is not required if an access token is supplied directly with the --azure-key-vault-accesstoken option or when using managed identities with --azure-key-vault-managed-identity. If this parameter is supplied, --azure-key-vault-client-id and --azure-key-vault-client-secret must be supplied as well." + }, + { + "name": "KeyVaultCertificateName", + "type": "string", + "format": "--azure-key-vault-certificate {value}", + "secret": false, + "help": "The name of the certificate used to perform the signing operation." + }, + { + "name": "KeyVaultAccessToken", + "type": "string", + "format": "--azure-key-vault-accesstoken {value}", + "secret": true, + "help": "An access token used to authenticate to Azure. This can be used instead of the --azure-key-vault-managed-identity, --azure-key-vault-client-id and --azure-key-vault-client-secret options. This is useful if NuGetKeyVaultSignTool is being used as part of another program that is already authenticated and has an access token to Azure." + }, + { + "name": "KeyVaultManagedIdentity", + "type": "bool", + "format": "--azure-key-vault-managed-identity", + "secret": false, + "help": "Use the ambient Managed Identity to authenticate to Azure. This can be used instead of the --azure-key-vault-accesstoken, --azure-key-vault-client-id and --azure-key-vault-client-secret options. This is useful if NuGetKeyVaultSignTool is being used on a VM/service/CLI that is configured for managed identities to Azure." + }, + { + "name": "TimestampRfc3161Url", + "type": "string", + "format": "--timestamp-rfc3161 {value}", + "help": "A URL to an RFC3161 compliant timestamping service. This parameter serves the same purpose as the /tr option in the Windows SDK signtool. This parameter should be used in favor of the --timestamp option. Using this parameter will allow using modern, RFC3161 timestamps which also support timestamp digest algorithms other than SHA1." + }, + { + "name": "TimestampDigest", + "type": "NuGetKeyVaultSignToolDigestAlgorithm", + "format": "--timestamp-digest {value}", + "help": "The name of the digest algorithm used for timestamping. This parameter is ignored unless the --timestamp-rfc3161 parameter is also supplied. The default value is sha256." + }, + { + "name": "FileDigest", + "type": "NuGetKeyVaultSignToolDigestAlgorithm", + "format": "--file-digest {value}", + "help": "The name of the digest algorithm used for hashing the file being signed. The default value is sha256." + }, + { + "name": "Force", + "type": "bool", + "format": "--force", + "help": "Overwrites a signature if it exists." + }, + { + "name": "Output", + "type": "string", + "format": "--output {value}", + "help": "The output file. If omitted, overwrites input." + } + ] + } + } + ], + "enumerations": [ + { + "name": "NuGetKeyVaultSignToolDigestAlgorithm", + "values": [ + "sha1", + "sha256", + "sha384", + "sha512" + ] + } + ] +} diff --git a/ricaun.Nuke/Utils/TestRunUtil.cs b/ricaun.Nuke/Utils/TestRunUtil.cs index 365b958..515c7d2 100644 --- a/ricaun.Nuke/Utils/TestRunUtil.cs +++ b/ricaun.Nuke/Utils/TestRunUtil.cs @@ -253,9 +253,9 @@ public static string GetDetailsTestReport(AbsolutePath resultFile) } #region Utils - const string IconFailed = ":x:"; - const string IconSkipped = ":warning:"; - const string IconPassed = ":heavy_check_mark:"; + const string IconFailed = ":red_circle:"; + const string IconSkipped = ":yellow_circle:"; + const string IconPassed = ":green_circle:"; /// /// GetIcon /// diff --git a/ricaun.Nuke/ricaun.Nuke.csproj b/ricaun.Nuke/ricaun.Nuke.csproj index 479f81d..698a957 100644 --- a/ricaun.Nuke/ricaun.Nuke.csproj +++ b/ricaun.Nuke/ricaun.Nuke.csproj @@ -3,20 +3,18 @@ net6.0 false + Latest ricaun.Nuke - 1.8.2 + 1.9.0 - - .Dev - - + ricaun Luiz Henrique Cassettari