From d30e5ef012ae7f52ec2a5d1d1915ab94a6560ace Mon Sep 17 00:00:00 2001 From: Alexandre Mutel Date: Mon, 6 May 2024 08:24:41 +0200 Subject: [PATCH] Add support for gist token --- .../DevHosting/GitHubDevHosting.cs | 103 +++++------------- src/dotnet-releaser/ReleaserApp.Changelog.cs | 2 +- .../ReleaserApp.Configuring.cs | 5 +- src/dotnet-releaser/ReleaserApp.DevHosting.cs | 4 +- src/dotnet-releaser/ReleaserApp.cs | 14 ++- 5 files changed, 44 insertions(+), 84 deletions(-) diff --git a/src/dotnet-releaser/DevHosting/GitHubDevHosting.cs b/src/dotnet-releaser/DevHosting/GitHubDevHosting.cs index d60a00a..45c0446 100644 --- a/src/dotnet-releaser/DevHosting/GitHubDevHosting.cs +++ b/src/dotnet-releaser/DevHosting/GitHubDevHosting.cs @@ -21,17 +21,21 @@ public class GitHubDevHosting : IDevHosting private readonly ISimpleLogger _log; private readonly string _url; private readonly string _apiToken; + private readonly string _gistApiToken; private readonly GitHubClient _client; - - public GitHubDevHosting(ISimpleLogger log, DevHostingConfiguration hostingConfiguration, string apiToken, string apiTokenUsage) + private readonly GitHubClient _clientGist; + + public GitHubDevHosting(ISimpleLogger log, DevHostingConfiguration hostingConfiguration, string apiToken, string apiTokenUsage, string? gistApiToken = null) { Logger = log; Configuration = hostingConfiguration; _log = log; _url = hostingConfiguration.Base; _apiToken = apiToken; + _gistApiToken = gistApiToken ?? apiToken; ApiTokenUsage = apiTokenUsage; _client = new GitHubClient(new ProductHeaderValue(nameof(ReleaserApp)), new Uri(hostingConfiguration.Api)); + _clientGist = new GitHubClient(new ProductHeaderValue(nameof(ReleaserApp)), new Uri(hostingConfiguration.Api)); } public ISimpleLogger Logger { get; } @@ -44,7 +48,7 @@ public GitHubDevHosting(ISimpleLogger log, DevHostingConfiguration hostingConfig public async Task Connect() { - var tokenAuth = new Credentials(_apiToken); // NOTE: not real token + var tokenAuth = new Credentials(_apiToken); _client.Credentials = tokenAuth; _log.Info($"Connecting to GitHub ({ApiTokenUsage})"); @@ -57,6 +61,13 @@ public async Task Connect() _log.Error($"Unable to connect GitHub ({ApiTokenUsage}). Reason: {ex.Message}"); return false; } + + _clientGist.Credentials = tokenAuth; + if (_gistApiToken != _apiToken) + { + _clientGist.Credentials = new Credentials(_gistApiToken); + } + return true; } @@ -76,7 +87,17 @@ public async Task> GetAllReleaseTags(string user, string re public async Task CreateOrUpdateGist(string gistId, string fileName, string content) { - var gist = await _client.Gist.Get(gistId); + Gist gist; + try + { + gist = await _clientGist.Gist.Get(gistId); + } + catch (Exception ex) + { + _log.Error($"Unable to get the gist {gistId}. Reason: {ex.Message}"); + return; + } + if (gist is null) { _log.Error($"The gist {gistId} for code coverage was not found"); @@ -96,81 +117,11 @@ public async Task CreateOrUpdateGist(string gistId, string fileName, string cont GistUpdate gistUpdate = new GistUpdate(); //gistUpdate.Files.Add(); gistUpdate.Files.Add(fileName, new GistFileUpdate() { NewFileName = fileName, Content = content }); - await _client.Gist.Edit(gistId, gistUpdate); + await _clientGist.Gist.Edit(gistId, gistUpdate); } else { - if (!gist.GitPushUrl.StartsWith("https://")) - { - _log.Warn($"The gist URL {gist.GitPushUrl} is not a standard gist URL and cannot be updated."); - return; - } - - var uri = new Uri(gist.GitPushUrl); - var gitCloneUrl = $"git@{uri.Host}:{uri.PathAndQuery.TrimStart('/')}"; - - var gistTempDirectory = Directory.CreateTempSubdirectory("dotnet-releaser-gist"); - try - { - var result = await GitRunner.Run("clone", new[] { gitCloneUrl, gistTempDirectory.FullName }); - - if (result.HasErrors) - { - _log.Error($"Unable to clone the gist {gistId} to {gistTempDirectory.FullName}. ExitCode: {result.CommandResult.ExitCode}, Output: {result.Output}"); - return; - } - - var gistFile = Path.Combine(gistTempDirectory.FullName, fileName); - await File.WriteAllTextAsync(gistFile, content); - - result = await GitRunner.Run("config", new[] { "--local", "user.email", "action@github.com" }, gistTempDirectory.FullName); - if (result.HasErrors) - { - _log.Error($"Unable to set the user.email for the git repository. ExitCode: {result.CommandResult.ExitCode}, Output: {result.Output}"); - return; - } - - result = await GitRunner.Run("config", new[] { "--local", "user.name", "GitHub Action" }, gistTempDirectory.FullName); - if (result.HasErrors) - { - _log.Error($"Unable to set the user.name for the git repository. ExitCode: {result.CommandResult.ExitCode}, Output: {result.Output}"); - return; - } - - result = await GitRunner.Run("add", new[] { "." }, gistTempDirectory.FullName); - if (result.HasErrors) - { - _log.Error($"Unable to add the file {fileName} to the git repository. ExitCode: {result.CommandResult.ExitCode}, Output: {result.Output}"); - return; - } - - result = await GitRunner.Run("commit", new[] { "-m", $"Upload new file {fileName}" }, gistTempDirectory.FullName); - if (result.HasErrors) - { - _log.Error($"Unable to commit the file {fileName} to the git repository. ExitCode: {result.CommandResult.ExitCode}, Output: {result.Output}"); - return; - } - - result = await GitRunner.Run("push", Array.Empty(), gistTempDirectory.FullName); - if (result.HasErrors) - { - _log.Error($"Unable to push the file {fileName} to the git repository. ExitCode: {result.CommandResult.ExitCode}, Output: {result.Output}"); - return; - } - } - finally - { - try - { - gistTempDirectory.Delete(true); - } - catch - { - // ignore - } - } - - _log.Warn($"New file uploaded to gist {gistId}"); + _log.Error($"The gist {gistId} does not contain a file {fileName}"); } } diff --git a/src/dotnet-releaser/ReleaserApp.Changelog.cs b/src/dotnet-releaser/ReleaserApp.Changelog.cs index c954d13..1b6bf4e 100644 --- a/src/dotnet-releaser/ReleaserApp.Changelog.cs +++ b/src/dotnet-releaser/ReleaserApp.Changelog.cs @@ -26,7 +26,7 @@ private async Task ListOrUpdateChangelog(string configurationFilePath, str return false; } - var devHosting = await ConnectToDevHosting(_config.GitHub, githubApiToken, "For Fetching Changelog"); + var devHosting = await ConnectToDevHosting(_config.GitHub, githubApiToken, "For Fetching Changelog", null); if (devHosting is null) return false; return await ListOrUpdateChangelog(devHosting, version, update); diff --git a/src/dotnet-releaser/ReleaserApp.Configuring.cs b/src/dotnet-releaser/ReleaserApp.Configuring.cs index dbda49b..e35b4c8 100644 --- a/src/dotnet-releaser/ReleaserApp.Configuring.cs +++ b/src/dotnet-releaser/ReleaserApp.Configuring.cs @@ -15,7 +15,8 @@ namespace DotNetReleaser; public partial class ReleaserApp { - private async Task<(BuildInformation? buildInformation, IDevHosting? devHosting, IDevHosting? devHostingExtra)?> Configuring(string configurationFile, BuildKind buildKind, string githubApiToken, string? githubApiTokenExtra, string? nugetApiToken, bool forceArtifactsFolder, string? publishVersion) + private async Task<(BuildInformation? buildInformation, IDevHosting? devHosting, IDevHosting? devHostingExtra)?> Configuring(string configurationFile, BuildKind buildKind, string githubApiToken, string? githubApiTokenExtra, + string? githubApiTokenGist, string? nugetApiToken, bool forceArtifactsFolder, string? publishVersion) { // ------------------------------------------------------------------ // Load Configuration @@ -53,7 +54,7 @@ public partial class ReleaserApp // Connect to GitHub if we have a token if (!string.IsNullOrEmpty(githubApiToken)) { - devHosting = await ConnectToDevHosting(hostingConfiguration, githubApiToken, "For this CI"); + devHosting = await ConnectToDevHosting(hostingConfiguration, githubApiToken, "For this CI", githubApiTokenGist); if (devHosting is null) { return null; // return false; diff --git a/src/dotnet-releaser/ReleaserApp.DevHosting.cs b/src/dotnet-releaser/ReleaserApp.DevHosting.cs index 9c1c7bf..c3cdf0d 100644 --- a/src/dotnet-releaser/ReleaserApp.DevHosting.cs +++ b/src/dotnet-releaser/ReleaserApp.DevHosting.cs @@ -6,9 +6,9 @@ namespace DotNetReleaser; public partial class ReleaserApp { - private async Task ConnectToDevHosting(DevHostingConfiguration hostingConfiguration, string githubApiToken, string apiTokenUsage) + private async Task ConnectToDevHosting(DevHostingConfiguration hostingConfiguration, string githubApiToken, string apiTokenUsage, string? githubApiTokenGist = null) { - var hosting = new GitHubDevHosting(_logger, hostingConfiguration, githubApiToken, apiTokenUsage); + var hosting = new GitHubDevHosting(_logger, hostingConfiguration, githubApiToken, apiTokenUsage, githubApiTokenGist); if (await hosting.Connect()) { diff --git a/src/dotnet-releaser/ReleaserApp.cs b/src/dotnet-releaser/ReleaserApp.cs index e555d6e..01653e5 100644 --- a/src/dotnet-releaser/ReleaserApp.cs +++ b/src/dotnet-releaser/ReleaserApp.cs @@ -174,6 +174,11 @@ CommandOption AddGitHubTokenExtra(CommandLineApplication cmd) return cmd.Option("--github-token-extra ", "GitHub Api Token. Required if publish homebrew to GitHub is true in the config file. In that case dotnet-releaser needs a personal access GitHub token which can create the homebrew repository. This token has usually more access than the --github-token that is only used for the current repository. ", CommandOptionType.SingleValue); } + CommandOption AddGitHubTokenGist(CommandLineApplication cmd) + { + return cmd.Option("--github-token-gist ", "GitHub Api Token. Required if publishing to a gist used for e.g coverage.", CommandOptionType.SingleValue); + } + CommandArgument AddTomlConfigurationArgument(CommandLineApplication cmd, bool forNew) { var arg = cmd.Argument("dotnet-releaser.toml", forNew ? "TOML configuration file path to create. Default is: dotnet-releaser.toml" : "The input TOML configuration file."); @@ -185,6 +190,7 @@ void AddPublishOrBuildArgs(CommandLineApplication cmd) { CommandOption? nugetToken = null; CommandOption? gitHubTokenExtra = null; + CommandOption? gitHubTokenGist = null; CommandOption? skipAppPackagesOption = null; var githubToken = AddGitHubToken(cmd); @@ -195,6 +201,7 @@ void AddPublishOrBuildArgs(CommandLineApplication cmd) nugetToken = cmd.Option("--nuget-token ", "NuGet Api Token. Required if publish to NuGet is true in the config file", CommandOptionType.SingleValue); gitHubTokenExtra = AddGitHubTokenExtra(cmd); + gitHubTokenGist = AddGitHubTokenGist(cmd); } else { @@ -237,7 +244,7 @@ void AddPublishOrBuildArgs(CommandLineApplication cmd) { appReleaser._tableBorder = GetTableBorderFromKind(tableKindOption.ParsedValue); } - var result = await appReleaser.RunImpl(configurationFilePath, buildKind, githubToken.ParsedValue, gitHubTokenExtra?.ParsedValue, nugetToken?.ParsedValue, forceOption.ParsedValue, forceUploadOption?.ParsedValue ?? false, publishVersion?.ParsedValue); + var result = await appReleaser.RunImpl(configurationFilePath, buildKind, githubToken.ParsedValue, gitHubTokenExtra?.ParsedValue, gitHubTokenGist?.ParsedValue, nugetToken?.ParsedValue, forceOption.ParsedValue, forceUploadOption?.ParsedValue ?? false, publishVersion?.ParsedValue); return result ? 0 : 1; }); } @@ -299,7 +306,8 @@ private async Task LoadConfiguration(string configurationFile) /// /// Runs the releaser app /// - private async Task RunImpl(string configurationFile, BuildKind buildKind, string githubApiToken, string? githubApiTokenExtra, string? nugetApiToken, bool forceArtifactsFolder, bool forceUpload, string? publishVersion) + private async Task RunImpl(string configurationFile, BuildKind buildKind, string githubApiToken, string? githubApiTokenExtra, string? gitHubTokenGist, string? nugetApiToken, bool forceArtifactsFolder, bool forceUpload, + string? publishVersion) { BuildInformation? buildInformation = null; GitHubDevHostingConfiguration? hostingConfiguration = null; @@ -310,7 +318,7 @@ private async Task RunImpl(string configurationFile, BuildKind buildKind, { _logger.Info($"dotnet-releaser {Version} - {buildKind.ToString().ToLowerInvariant()}"); _logger.LogStartGroup($"Configuring"); - var result = await Configuring(configurationFile, buildKind, githubApiToken, githubApiTokenExtra, nugetApiToken, forceArtifactsFolder, publishVersion); + var result = await Configuring(configurationFile, buildKind, githubApiToken, githubApiTokenExtra, gitHubTokenGist, nugetApiToken, forceArtifactsFolder, publishVersion); if (result is null) return false; buildInformation = result.Value.buildInformation!; devHosting = result.Value.devHosting;