diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 391f6626..aea13b83 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -22,13 +22,15 @@ jobs: with: fetch-depth: 0 - - name: Setup .NET SDK + - name: Setup .NET SDK (net8.0, net9.0) uses: actions/setup-dotnet@v5 with: dotnet-version: | 8.0.x 9.0.x - 10.0.x + + - name: Setup .NET SDK (global.json) + uses: actions/setup-dotnet@v5 - name: Build shell: bash diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 47f8f32f..9d0d9119 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -21,28 +21,38 @@ jobs: build: name: Publish NuGet Packages if: "!contains(github.event.head_commit.message, 'skip-ci') || startsWith(github.ref, 'refs/tags/')" - runs-on: ubuntu-latest + runs-on: windows-latest steps: - name: Checkout uses: actions/checkout@v5 with: fetch-depth: 0 - - name: Setup .NET SDK + - name: Azure login + uses: azure/login@v2 + with: + client-id: ${{ secrets.AZURE_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_TENANT_ID }} + subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + + - name: Setup .NET SDK (net8.0, net9.0) uses: actions/setup-dotnet@v5 with: dotnet-version: | 8.0.x 9.0.x - 10.0.x + + - name: Setup .NET SDK (global.json) + uses: actions/setup-dotnet@v5 - name: Publish shell: bash run: | dotnet tool restore - dotnet make publish \ + dotnet make publish --sign \ --nuget-key="${{secrets.NUGET_API_KEY}}" \ - --github-key="${{secrets.GITHUB_TOKEN}}" + --keyvaultUrl="${{secrets.SIGN_KEYVAULT_URL}}" \ + --keyvaultCertificate="${{secrets.SIGN_KEYVAULT_CERTIFICATE}}" ################################################### # DOCS diff --git a/.gitignore b/.gitignore index 664051de..537737dd 100644 --- a/.gitignore +++ b/.gitignore @@ -8,8 +8,8 @@ .idea .DS_Store -# Cakeup -cakeup-x86_64-latest.exe +# Sign tool +.sign # .NET Core CLI /.dotnet/ diff --git a/build.cs b/build.cs index 3a64cc62..81da16f4 100644 --- a/build.cs +++ b/build.cs @@ -45,9 +45,10 @@ Task("Build") Task("Test") .IsDependentOn("Build") - .Does(ctx => + .Does(ctx => { - ctx.DotNetTest(testProject, new DotNetTestSettings { + ctx.DotNetTest(testProject, new DotNetTestSettings + { Configuration = configuration, Verbosity = DotNetVerbosity.Minimal, NoLogo = true, @@ -73,18 +74,66 @@ Task("Package") }); }); +Task("Sign-Binaries") + .IsDependentOn("Package") + .WithCriteria(ctx => ctx.HasArgument("sign"), "Not signing binaries") + .Does(ctx => +{ + // Ensure the sign tool is installed + ctx.StartProcess("dotnet", new ProcessSettings + { + Arguments = "tool install --tool-path .sign --prerelease sign" + }); + + var commandSettings = new CommandSettings + { + ToolExecutableNames = ["sign", "sign.exe"], + ToolName = "sign", + ToolPath = ResolveSignTool("sign.exe") + ?? ResolveSignTool("sign") + ?? throw new Exception("Failed to locate sign tool"), + }; + + var files = ctx.GetFiles("./.artifacts/*.nupkg"); + foreach (var file in files) + { + ctx.Information("Signing {0}...", file.FullPath); + + var arguments = new ProcessArgumentBuilder() + .Append("code") + .Append("azure-key-vault") + .AppendQuoted(file.FullPath) + .AppendSwitchQuoted("--file-list", ctx.MakeAbsolute(ctx.File("./resources/signclient.filter")).FullPath) + .AppendSwitchQuoted("--publisher-name", "Spectre Console") + .AppendSwitchQuoted("--description", "A .NET library that makes it easier to create beautiful console applications.") + .AppendSwitchQuoted("--description-url", "https://spectreconsole.net") + .AppendSwitchQuoted("--azure-credential-type", "azure-cli") + .AppendSwitchQuotedSecret("--azure-key-vault-certificate", Argument("keyvaultCertificate")) + .AppendSwitchQuotedSecret("--azure-key-vault-url", Argument("keyvaultUrl")); + + ctx.Command(commandSettings, arguments); + ctx.Information("Done signing {0}.", file.FullPath); + } + + FilePath? ResolveSignTool(string name) + { + var path = ctx.MakeAbsolute(ctx.Directory(".sign").Path.CombineWithFilePath(name)); + return ctx.FileExists(path) ? path : null; + } +}); + Task("Publish-NuGet") .WithCriteria(ctx => BuildSystem.IsRunningOnGitHubActions, "Not running on GitHub Actions") - .IsDependentOn("Package") - .Does(ctx => + .IsDependentOn("Sign-Binaries") + .Does(ctx => { var apiKey = Argument("nuget-key", null); - if(string.IsNullOrWhiteSpace(apiKey)) { + if (string.IsNullOrWhiteSpace(apiKey)) + { throw new CakeException("No NuGet API key was provided."); } - // Publish to GitHub Packages - foreach(var file in ctx.GetFiles("./.artifacts/*.nupkg")) + foreach (var file in ctx.GetFiles("./.artifacts/*.nupkg")) { ctx.Information("Publishing {0}...", file.GetFilename().FullPath); DotNetNuGetPush(file.FullPath, new DotNetNuGetPushSettings diff --git a/resources/signclient.filter b/resources/signclient.filter new file mode 100644 index 00000000..2295bffe --- /dev/null +++ b/resources/signclient.filter @@ -0,0 +1 @@ +**/Spectre.Console* \ No newline at end of file