From 87d9a548fa6f016fca42c40bd267bd5136a662ae Mon Sep 17 00:00:00 2001 From: Xeevis Date: Tue, 18 Jun 2019 00:11:19 +0200 Subject: [PATCH 1/3] Support for update channels and SemVer in CLI --- .../Volo.Abp.Cli.Core.csproj | 1 + .../Volo/Abp/Cli/CliService.cs | 131 +++++++++++++----- .../Volo/Abp/Cli/NuGet/NuGetService.cs | 24 ++-- 3 files changed, 107 insertions(+), 49 deletions(-) diff --git a/framework/src/Volo.Abp.Cli.Core/Volo.Abp.Cli.Core.csproj b/framework/src/Volo.Abp.Cli.Core/Volo.Abp.Cli.Core.csproj index e181af68ac..64b113fba9 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo.Abp.Cli.Core.csproj +++ b/framework/src/Volo.Abp.Cli.Core/Volo.Abp.Cli.Core.csproj @@ -15,6 +15,7 @@ + diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs index 707550e11b..2a12004cab 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs @@ -1,12 +1,12 @@ -using System; -using System.Diagnostics; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using NuGet.Versioning; +using System; using System.IO; +using System.Linq; using System.Reflection; -using System.Runtime.InteropServices; -using Microsoft.Extensions.DependencyInjection; using System.Threading.Tasks; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; using Volo.Abp.Cli.Args; using Volo.Abp.Cli.Commands; using Volo.Abp.Cli.NuGet; @@ -18,7 +18,6 @@ namespace Volo.Abp.Cli public class CliService : ITransientDependency { public ILogger Logger { get; set; } - protected ICommandLineArgumentParser CommandLineArgumentParser { get; } protected ICommandSelector CommandSelector { get; } protected IHybridServiceScopeFactory ServiceScopeFactory { get; } @@ -40,11 +39,9 @@ namespace Volo.Abp.Cli public async Task RunAsync(string[] args) { - Logger.LogInformation($"ABP CLI, version {GetCliVersion()}."); - Logger.LogInformation("https://abp.io"); - - await CheckForNewVersion(); + Logger.LogInformation("ABP CLI (https://abp.io)"); + await CheckCliVersionAsync(); CheckDependencies(); var commandLineArgs = CommandLineArgumentParser.Parse(args); @@ -72,7 +69,7 @@ namespace Volo.Abp.Cli private void CheckDependencies() { var installedNpmPackages = CmdHelper.RunCmdAndGetOutput("npm list -g --depth 0"); - + if (!installedNpmPackages.Contains(" yarn@")) { InstallYarn(); @@ -95,47 +92,107 @@ namespace Volo.Abp.Cli CmdHelper.RunCmd("npm install gulp -g"); } - private async Task CheckForNewVersion() + private async Task CheckCliVersionAsync() { + var assembly = typeof(CliService).Assembly; + + var toolPath = assembly.Location.Contains(".store") ? assembly.Location.Substring(0, assembly.Location.IndexOf(".store")) : null; + SemanticVersion currentCliVersion = default; + + if (!string.IsNullOrEmpty(toolPath)) + { + var strReader = new StringReader(CmdHelper.RunCmdAndGetOutput($"dotnet tool list --tool-path {toolPath}")); + string output; + while ((output = await strReader.ReadLineAsync()) != null) + { + if (output.StartsWith("Volo.Abp.Cli", StringComparison.InvariantCultureIgnoreCase) && + SemanticVersion.TryParse(output.Split(new char[0], StringSplitOptions.RemoveEmptyEntries)[1], out var detectedVersion)) + { + currentCliVersion = detectedVersion; + } + } + } + + if (currentCliVersion == null) + { + // If not a tool executable, fallback to assembly version and treat as dev without updates + // Assembly revisions are not supported by SemVer scheme required for NuGet, trim to {major}.{minor}.{patch} + var assemblyVersion = string.Join(".", assembly.GetFileVersion().Split('.').Take(3)); + currentCliVersion = SemanticVersion.Parse(assemblyVersion + "-dev"); + } + + var updateChannel = + currentCliVersion.IsPrerelease ? + currentCliVersion.Release.Contains("preview") ? + UpdateChannel.Nightly + : currentCliVersion.Release.Contains("dev") ? + UpdateChannel.Development + : UpdateChannel.Prerelease + : UpdateChannel.Stable; + + Logger.LogInformation($"Version {currentCliVersion} ({updateChannel} channel)"); + try { - var currentVersion = GetCliVersion(); - var latestVersion = await NuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Cli"); + SemanticVersion latestVersion = default; - if (!latestVersion.IsNullOrEmpty() && currentVersion != latestVersion) + switch (updateChannel) { - Logger.LogInformation(""); - Logger.LogWarning("ABP CLI has a newer version (" + latestVersion + "). Please update to get the latest features and fixes."); + case UpdateChannel.Stable: + latestVersion = await NuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Cli"); + break; + + case UpdateChannel.Prerelease: + latestVersion = await NuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Cli", includePreviews: true); + break; + + case UpdateChannel.Nightly: + latestVersion = await NuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Cli", includeNightly: true); + break; + } + + if (latestVersion != null & latestVersion > currentCliVersion) + { + Logger.LogWarning($"ABP CLI has a newer {updateChannel.ToString().ToLowerInvariant()} version {latestVersion}, please update to get the latest features and fixes."); Logger.LogWarning(""); Logger.LogWarning("Update Command: "); - Logger.LogWarning(" dotnet tool update -g Volo.Abp.Cli"); + + // Update command doesn't support prerelease versions https://github.com/dotnet/sdk/issues/2551 workaround is to uninstall & install + switch (updateChannel) + { + case UpdateChannel.Stable: + Logger.LogWarning($" dotnet tool update --tool-path {toolPath} Volo.Abp.Cli"); + break; + + case UpdateChannel.Prerelease: + Logger.LogWarning($" dotnet tool uninstall --tool-path {toolPath} Volo.Abp.Cli"); + Logger.LogWarning($" dotnet tool install --tool-path {toolPath} --version {latestVersion} Volo.Abp.Cli"); + break; + + case UpdateChannel.Nightly: + Logger.LogWarning($" dotnet tool uninstall --tool-path {toolPath} Volo.Abp.Cli"); + Logger.LogWarning($" dotnet tool install --tool-path {toolPath} --add-source https://www.myget.org/F/abp-nightly/api/v3/index.json --version {latestVersion} Volo.Abp.Cli"); + break; + } + Logger.LogWarning(""); } + + return; } catch (Exception e) { - Logger.LogWarning("Could not get the latest version infom from NuGet.org:"); + Logger.LogWarning("Unable to retrieve the latest version"); Logger.LogWarning(e.Message); } } - private static string GetCliVersion() + protected enum UpdateChannel { - var version = typeof(CliService) - .Assembly - .GetFileVersion(); - - /* Assembly versions are like "2.4.0.0", but NuGet removes the last "0" here, - * like "2.4.0". - * So, we need to remove it from the assembly version to match to the NuGet version. - */ - - if (version.Split('.').Length == 4) - { - version = version.RemovePostFix(".0"); - } - - return version; + Development, + Stable, + Prerelease, + Nightly } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/NuGet/NuGetService.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/NuGet/NuGetService.cs index 115ce41d74..be0a444d0d 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/NuGet/NuGetService.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/NuGet/NuGetService.cs @@ -1,4 +1,5 @@ using Newtonsoft.Json; +using NuGet.Versioning; using System; using System.Collections.Generic; using System.Linq; @@ -23,16 +24,17 @@ namespace Volo.Abp.Cli.NuGet CancellationTokenProvider = cancellationTokenProvider; } - public async Task GetLatestVersionOrNullAsync(string packageId, bool includePreviews = false) + public async Task GetLatestVersionOrNullAsync(string packageId, bool includePreviews = false, bool includeNightly = false) { using (var client = new HttpClient()) { client.Timeout = TimeSpan.FromSeconds(30); - var responseMessage = await client.GetAsync( - $"https://api.nuget.org/v3-flatcontainer/{packageId.ToLowerInvariant()}/index.json", - CancellationTokenProvider.Token - ); + var url = includeNightly ? + $"https://www.myget.org/F/abp-nightly/api/v3/flatcontainer/{packageId.ToLowerInvariant()}/index.json" : + $"https://api.nuget.org/v3-flatcontainer/{packageId.ToLowerInvariant()}/index.json"; + + var responseMessage = await client.GetAsync(url, CancellationTokenProvider.Token); if (!responseMessage.IsSuccessStatusCode) { @@ -41,16 +43,14 @@ namespace Volo.Abp.Cli.NuGet var result = await responseMessage.Content.ReadAsStringAsync(); - var versions = JsonSerializer.Deserialize(result).Versions; + var versions = JsonSerializer.Deserialize(result).Versions.Select(x => SemanticVersion.Parse(x)); - if (!includePreviews) + if (!includePreviews && !includeNightly) { - versions = versions - .Where(x => !x.Contains("beta") && !x.Contains("preview") && !x.Contains("alpha") && !x.Contains("rc")) - .ToList(); + versions = versions.Where(x => !x.IsPrerelease); } - return versions.Count > 0 ? versions.Last() : null; + return versions.Any() ? versions.Max() : null; } } @@ -60,4 +60,4 @@ namespace Volo.Abp.Cli.NuGet public List Versions { get; set; } } } -} \ No newline at end of file +} From 228700fc27789249c352583094c97aee1e124ec2 Mon Sep 17 00:00:00 2001 From: Xeevis Date: Tue, 18 Jun 2019 00:11:28 +0200 Subject: [PATCH 2/3] Fix for VoloNugetPackagesVersionUpdater --- .../ProjectModification/VoloNugetPackagesVersionUpdater.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/VoloNugetPackagesVersionUpdater.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/VoloNugetPackagesVersionUpdater.cs index 545f5b0b05..5382dd744a 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/VoloNugetPackagesVersionUpdater.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/VoloNugetPackagesVersionUpdater.cs @@ -76,8 +76,8 @@ namespace Volo.Abp.Cli.ProjectModification var indexOfThirdQuote = content.IndexOf("\"", StringComparison.Ordinal); - var version = _nuGetService.GetLatestVersionOrNullAsync(packageId, includePreviews); - returningText.Append(version); + var version = _nuGetService.GetLatestVersionOrNullAsync(packageId, includePreviews).GetAwaiter().GetResult(); + returningText.Append(version.ToString()); index = indexOfPackageReference + packageReferenceStartText.Length + indexAfterQuote + indexAfterSecondQuote + indexOfThirdQuote; From 6d25b209982a211140ae68f0ca69b95125aa9e1a Mon Sep 17 00:00:00 2001 From: Yunus Emre Kalkan Date: Tue, 18 Jun 2019 10:27:21 +0300 Subject: [PATCH 3/3] refactor --- .../Volo/Abp/Cli/CliService.cs | 160 +++++++++++------- .../VoloNugetPackagesVersionUpdater.cs | 7 +- 2 files changed, 103 insertions(+), 64 deletions(-) diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs index 2a12004cab..68a5b5b03a 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs @@ -40,6 +40,7 @@ namespace Volo.Abp.Cli public async Task RunAsync(string[] args) { Logger.LogInformation("ABP CLI (https://abp.io)"); + Logger.LogInformation("https://abp.io"); await CheckCliVersionAsync(); CheckDependencies(); @@ -95,20 +96,54 @@ namespace Volo.Abp.Cli private async Task CheckCliVersionAsync() { var assembly = typeof(CliService).Assembly; + var toolPath = GetToolPath(assembly); + var currentCliVersion = await GetCurrentCliVersion(toolPath, assembly); + var updateChannel = GetUpdateChannel(currentCliVersion); - var toolPath = assembly.Location.Contains(".store") ? assembly.Location.Substring(0, assembly.Location.IndexOf(".store")) : null; - SemanticVersion currentCliVersion = default; + Logger.LogInformation($"Version {currentCliVersion} ({updateChannel} channel)"); + + try + { + var latestVersion = await GetLatestVersion(updateChannel); + if (latestVersion != null & latestVersion > currentCliVersion) + { + LogNewVersionInfo(updateChannel, latestVersion, toolPath); + } + } + catch (Exception e) + { + Logger.LogWarning("Unable to retrieve the latest version"); + Logger.LogWarning(e.Message); + } + } + + private static string GetToolPath(Assembly assembly) + { + if (!assembly.Location.Contains(".store")) + { + return null; + } + + return assembly.Location.Substring(0, assembly.Location.IndexOf(".store", StringComparison.Ordinal)); + } + + private async Task GetCurrentCliVersion(string toolPath, Assembly assembly) + { + SemanticVersion currentCliVersion = default; if (!string.IsNullOrEmpty(toolPath)) { - var strReader = new StringReader(CmdHelper.RunCmdAndGetOutput($"dotnet tool list --tool-path {toolPath}")); - string output; - while ((output = await strReader.ReadLineAsync()) != null) + var consoleOutput = new StringReader(CmdHelper.RunCmdAndGetOutput($"dotnet tool list --tool-path {toolPath}")); + string line; + while ((line = await consoleOutput.ReadLineAsync()) != null) { - if (output.StartsWith("Volo.Abp.Cli", StringComparison.InvariantCultureIgnoreCase) && - SemanticVersion.TryParse(output.Split(new char[0], StringSplitOptions.RemoveEmptyEntries)[1], out var detectedVersion)) + if (line.StartsWith("Volo.Abp.Cli", StringComparison.InvariantCultureIgnoreCase)) { - currentCliVersion = detectedVersion; + var version = line.Split(new char[0], StringSplitOptions.RemoveEmptyEntries)[1]; + + SemanticVersion.TryParse(version, out currentCliVersion); + + break; } } } @@ -118,73 +153,76 @@ namespace Volo.Abp.Cli // If not a tool executable, fallback to assembly version and treat as dev without updates // Assembly revisions are not supported by SemVer scheme required for NuGet, trim to {major}.{minor}.{patch} var assemblyVersion = string.Join(".", assembly.GetFileVersion().Split('.').Take(3)); - currentCliVersion = SemanticVersion.Parse(assemblyVersion + "-dev"); + return SemanticVersion.Parse(assemblyVersion + "-dev"); } - var updateChannel = - currentCliVersion.IsPrerelease ? - currentCliVersion.Release.Contains("preview") ? - UpdateChannel.Nightly - : currentCliVersion.Release.Contains("dev") ? - UpdateChannel.Development - : UpdateChannel.Prerelease - : UpdateChannel.Stable; + return currentCliVersion; + } - Logger.LogInformation($"Version {currentCliVersion} ({updateChannel} channel)"); + private static UpdateChannel GetUpdateChannel(SemanticVersion currentCliVersion) + { + if (!currentCliVersion.IsPrerelease) + { + return UpdateChannel.Stable; + } - try + if (currentCliVersion.Release.Contains("preview")) { - SemanticVersion latestVersion = default; + return UpdateChannel.Nightly; + } - switch (updateChannel) - { - case UpdateChannel.Stable: - latestVersion = await NuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Cli"); - break; + if (currentCliVersion.Release.Contains("dev")) + { + return UpdateChannel.Development; + } - case UpdateChannel.Prerelease: - latestVersion = await NuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Cli", includePreviews: true); - break; + return UpdateChannel.Prerelease; + } - case UpdateChannel.Nightly: - latestVersion = await NuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Cli", includeNightly: true); - break; - } + private async Task GetLatestVersion(UpdateChannel updateChannel) + { + switch (updateChannel) + { + case UpdateChannel.Stable: + return await NuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Cli"); - if (latestVersion != null & latestVersion > currentCliVersion) - { - Logger.LogWarning($"ABP CLI has a newer {updateChannel.ToString().ToLowerInvariant()} version {latestVersion}, please update to get the latest features and fixes."); - Logger.LogWarning(""); - Logger.LogWarning("Update Command: "); + case UpdateChannel.Prerelease: + return await NuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Cli", includePreviews: true); - // Update command doesn't support prerelease versions https://github.com/dotnet/sdk/issues/2551 workaround is to uninstall & install - switch (updateChannel) - { - case UpdateChannel.Stable: - Logger.LogWarning($" dotnet tool update --tool-path {toolPath} Volo.Abp.Cli"); - break; - - case UpdateChannel.Prerelease: - Logger.LogWarning($" dotnet tool uninstall --tool-path {toolPath} Volo.Abp.Cli"); - Logger.LogWarning($" dotnet tool install --tool-path {toolPath} --version {latestVersion} Volo.Abp.Cli"); - break; - - case UpdateChannel.Nightly: - Logger.LogWarning($" dotnet tool uninstall --tool-path {toolPath} Volo.Abp.Cli"); - Logger.LogWarning($" dotnet tool install --tool-path {toolPath} --add-source https://www.myget.org/F/abp-nightly/api/v3/index.json --version {latestVersion} Volo.Abp.Cli"); - break; - } + case UpdateChannel.Nightly: + return await NuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Cli", includeNightly: true); + default: + return default; + } + } - Logger.LogWarning(""); - } + private void LogNewVersionInfo(UpdateChannel updateChannel, SemanticVersion latestVersion, string toolPath) + { + Logger.LogWarning( + $"ABP CLI has a newer {updateChannel.ToString().ToLowerInvariant()} version {latestVersion}, please update to get the latest features and fixes."); + Logger.LogWarning(""); + Logger.LogWarning("Update Command: "); - return; - } - catch (Exception e) + // Update command doesn't support prerelease versions https://github.com/dotnet/sdk/issues/2551 workaround is to uninstall & install + switch (updateChannel) { - Logger.LogWarning("Unable to retrieve the latest version"); - Logger.LogWarning(e.Message); + case UpdateChannel.Stable: + Logger.LogWarning($" dotnet tool update --tool-path {toolPath} Volo.Abp.Cli"); + break; + + case UpdateChannel.Prerelease: + Logger.LogWarning($" dotnet tool uninstall --tool-path {toolPath} Volo.Abp.Cli"); + Logger.LogWarning($" dotnet tool install --tool-path {toolPath} --version {latestVersion} Volo.Abp.Cli"); + break; + + case UpdateChannel.Nightly: + Logger.LogWarning($" dotnet tool uninstall --tool-path {toolPath} Volo.Abp.Cli"); + Logger.LogWarning( + $" dotnet tool install --tool-path {toolPath} --add-source https://www.myget.org/F/abp-nightly/api/v3/index.json --version {latestVersion} Volo.Abp.Cli"); + break; } + + Logger.LogWarning(""); } protected enum UpdateChannel diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/VoloNugetPackagesVersionUpdater.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/VoloNugetPackagesVersionUpdater.cs index 5382dd744a..6312af0358 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/VoloNugetPackagesVersionUpdater.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/VoloNugetPackagesVersionUpdater.cs @@ -3,6 +3,7 @@ using System.IO; using System.Text; using Volo.Abp.Cli.NuGet; using Volo.Abp.DependencyInjection; +using Volo.Abp.Threading; namespace Volo.Abp.Cli.ProjectModification { @@ -75,9 +76,9 @@ namespace Volo.Abp.Cli.ProjectModification content = content.Substring(indexAfterSecondQuote); var indexOfThirdQuote = content.IndexOf("\"", StringComparison.Ordinal); - - var version = _nuGetService.GetLatestVersionOrNullAsync(packageId, includePreviews).GetAwaiter().GetResult(); - returningText.Append(version.ToString()); + + var version = AsyncHelper.RunSync(() => _nuGetService.GetLatestVersionOrNullAsync(packageId, includePreviews)); + returningText.Append(version); index = indexOfPackageReference + packageReferenceStartText.Length + indexAfterQuote + indexAfterSecondQuote + indexOfThirdQuote;