diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs index 34bf95fdf1..63fb4f8eee 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs @@ -30,6 +30,8 @@ namespace Volo.Abp.Cli options.Commands["login"] = typeof(LoginCommand); options.Commands["logout"] = typeof(LogoutCommand); options.Commands["suite"] = typeof(SuiteCommand); + options.Commands["switch-to-preview"] = typeof(SwitchNightlyPreviewCommand); + options.Commands["switch-to-stable"] = typeof(SwitchStableCommand); }); } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SwitchNightlyPreviewCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SwitchNightlyPreviewCommand.cs new file mode 100644 index 0000000000..9f0862258f --- /dev/null +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SwitchNightlyPreviewCommand.cs @@ -0,0 +1,44 @@ +using System.Text; +using System.Threading.Tasks; +using Volo.Abp.Cli.Args; +using Volo.Abp.Cli.ProjectModification; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Cli.Commands +{ + public class SwitchNightlyPreviewCommand : IConsoleCommand, ITransientDependency + { + private readonly PackageSourceSwitcher _packageSourceSwitcher; + + public SwitchNightlyPreviewCommand(PackageSourceSwitcher packageSourceSwitcher) + { + _packageSourceSwitcher = packageSourceSwitcher; + } + + public async Task ExecuteAsync(CommandLineArgs commandLineArgs) + { + await _packageSourceSwitcher.SwitchToPreview(commandLineArgs); + } + + public string GetUsageInfo() + { + var sb = new StringBuilder(); + + sb.AppendLine(""); + sb.AppendLine("Usage:"); + sb.AppendLine(" abp switch-to-preview [options]"); + sb.AppendLine(""); + sb.AppendLine("Options:"); + sb.AppendLine("-sp|--solution-path"); + sb.AppendLine(""); + sb.AppendLine("See the documentation for more info: https://docs.abp.io/en/abp/latest/CLI"); + + return sb.ToString(); + } + + public string GetShortDescription() + { + return "Switches packages to nightly preview ABP version."; + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SwitchStableCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SwitchStableCommand.cs new file mode 100644 index 0000000000..333583e96d --- /dev/null +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SwitchStableCommand.cs @@ -0,0 +1,44 @@ +using System.Text; +using System.Threading.Tasks; +using Volo.Abp.Cli.Args; +using Volo.Abp.Cli.ProjectModification; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Cli.Commands +{ + public class SwitchStableCommand : IConsoleCommand, ITransientDependency + { + private readonly PackageSourceSwitcher _packageSourceSwitcher; + + public SwitchStableCommand(PackageSourceSwitcher packageSourceSwitcher) + { + _packageSourceSwitcher = packageSourceSwitcher; + } + + public async Task ExecuteAsync(CommandLineArgs commandLineArgs) + { + await _packageSourceSwitcher.SwitchToStable(commandLineArgs); + } + + public string GetUsageInfo() + { + var sb = new StringBuilder(); + + sb.AppendLine(""); + sb.AppendLine("Usage:"); + sb.AppendLine(" abp switch-to-stable [options]"); + sb.AppendLine(""); + sb.AppendLine("Options:"); + sb.AppendLine("-sp|--solution-path"); + sb.AppendLine(""); + sb.AppendLine("See the documentation for more info: https://docs.abp.io/en/abp/latest/CLI"); + + return sb.ToString(); + } + + public string GetShortDescription() + { + return "Switches packages to stable ABP version from preview version."; + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/UpdateCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/UpdateCommand.cs index d201790c94..c44f77b749 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/UpdateCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/UpdateCommand.cs @@ -42,13 +42,13 @@ namespace Volo.Abp.Cli.Commands if (updateNpm || !updateNuget) { - UpdateNpmPackages(directory); + await UpdateNpmPackages(directory); } } - private void UpdateNpmPackages(string directory) + private async Task UpdateNpmPackages(string directory) { - _npmPackagesUpdater.Update(directory); + await _npmPackagesUpdater.Update(directory); } private async Task UpdateNugetPackages(CommandLineArgs commandLineArgs, string directory) @@ -94,7 +94,7 @@ namespace Volo.Abp.Cli.Commands sb.AppendLine(""); sb.AppendLine("Usage:"); sb.AppendLine(""); - sb.AppendLine(" abp update [options]"); + sb.AppendLine(" abp update [options]"); sb.AppendLine(""); sb.AppendLine("Options:"); sb.AppendLine("-p|--include-previews (if supported by the template)"); diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/MyGetApiResponse.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/MyGetApiResponse.cs new file mode 100644 index 0000000000..9a32d8d6fc --- /dev/null +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/MyGetApiResponse.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; + +namespace Volo.Abp.Cli.ProjectModification +{ + public class MyGetApiResponse + { + public string _date { get; set; } + + public List Packages { get; set; } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/MyGetPackage.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/MyGetPackage.cs new file mode 100644 index 0000000000..e5ef40ca17 --- /dev/null +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/MyGetPackage.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; + +namespace Volo.Abp.Cli.ProjectModification +{ + public class MyGetPackage + { + public string PackageType { get; set; } + + public string Id { get; set; } + + public List Versions { get; set; } + + public List Dates { get; set; } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/MyGetPackageListFinder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/MyGetPackageListFinder.cs new file mode 100644 index 0000000000..41907276f4 --- /dev/null +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/MyGetPackageListFinder.cs @@ -0,0 +1,51 @@ +using System; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Newtonsoft.Json; +using Volo.Abp.Cli.Http; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Cli.ProjectModification +{ + public class MyGetPackageListFinder : ISingletonDependency + { + private MyGetApiResponse _response; + + public ILogger Logger { get; set; } + + public MyGetPackageListFinder() + { + Logger = NullLogger.Instance; + } + + public async Task GetPackages() + { + if (_response != null) + { + return _response; + } + + try + { + using (var client = new CliHttpClient(TimeSpan.FromMinutes(10))) + { + var responseMessage = await client.GetAsync( + $"{CliUrls.WwwAbpIo}api/myget/packages/" + ); + + _response = JsonConvert.DeserializeObject(Encoding.Default.GetString(await responseMessage.Content.ReadAsByteArrayAsync())); + } + } + catch (Exception) + { + Logger.LogError("Unable to get latest preview version."); + throw; + } + + return _response; + } + + } +} diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs index 41fd33b4fb..91eaec48e7 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; +using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Newtonsoft.Json; @@ -18,18 +19,20 @@ namespace Volo.Abp.Cli.ProjectModification private readonly PackageJsonFileFinder _packageJsonFileFinder; private readonly NpmGlobalPackagesChecker _npmGlobalPackagesChecker; + private readonly MyGetPackageListFinder _myGetPackageListFinder; private readonly Dictionary _fileVersionStorage = new Dictionary(); - public NpmPackagesUpdater(PackageJsonFileFinder packageJsonFileFinder, NpmGlobalPackagesChecker npmGlobalPackagesChecker) + public NpmPackagesUpdater(PackageJsonFileFinder packageJsonFileFinder, NpmGlobalPackagesChecker npmGlobalPackagesChecker, MyGetPackageListFinder myGetPackageListFinder) { _packageJsonFileFinder = packageJsonFileFinder; _npmGlobalPackagesChecker = npmGlobalPackagesChecker; + _myGetPackageListFinder = myGetPackageListFinder; Logger = NullLogger.Instance; } - public void Update(string rootDirectory) + public async Task Update(string rootDirectory, bool includePreviews = false, bool switchToStable = false) { var fileList = _packageJsonFileFinder.Find(rootDirectory); @@ -42,7 +45,7 @@ namespace Volo.Abp.Cli.ProjectModification foreach (var file in fileList) { - UpdatePackagesInFile(file, out var packagesUpdated); + var packagesUpdated = await UpdatePackagesInFile(file, includePreviews, switchToStable); if (packagesUpdated) { @@ -64,21 +67,21 @@ namespace Volo.Abp.Cli.ProjectModification return File.Exists(Path.Combine(fileDirectory, "angular.json")); } - protected virtual void UpdatePackagesInFile(string file, out bool packagesUpdated) + protected virtual async Task UpdatePackagesInFile(string file, bool includePreviews = false, bool switchToStable = false) { - packagesUpdated = false; + var packagesUpdated = false; var fileContent = File.ReadAllText(file); var packageJson = JObject.Parse(fileContent); var abpPackages = GetAbpPackagesFromPackageJson(packageJson); if (!abpPackages.Any()) { - return; + return packagesUpdated; } foreach (var abpPackage in abpPackages) { - TryUpdatePackage(file, abpPackage, out var updated); + var updated = await TryUpdatePackage(file, abpPackage, includePreviews, switchToStable); if (updated) { @@ -89,18 +92,23 @@ namespace Volo.Abp.Cli.ProjectModification var modifiedFileContent = packageJson.ToString(Formatting.Indented); File.WriteAllText(file, modifiedFileContent); + + return packagesUpdated; } - protected virtual void TryUpdatePackage(string file, JProperty package, out bool updated) + protected virtual async Task TryUpdatePackage(string file, JProperty package, + bool includePreviews = false, bool switchToStable = false) { - var version = GetLatestVersion(package); + var updated = false; + var currentVersion = (string)package.Value; + + var version = await GetLatestVersion(package, currentVersion, includePreviews, switchToStable); var versionWithPrefix = $"^{version}"; - if (versionWithPrefix == (string)package.Value) + if (versionWithPrefix == currentVersion) { - updated = false; - return; + return false; } else { @@ -110,25 +118,41 @@ namespace Volo.Abp.Cli.ProjectModification package.Value.Replace(versionWithPrefix); Logger.LogInformation($"Updated {package.Name} to {version} in {file.Replace(Directory.GetCurrentDirectory(), "")}."); + return updated; } - protected virtual string GetLatestVersion(JProperty package) + protected virtual async Task GetLatestVersion(JProperty package, string currentVersion, + bool includePreviews = false, bool switchToStable = false) { if (_fileVersionStorage.ContainsKey(package.Name)) { return _fileVersionStorage[package.Name]; } - var version = CmdHelper.RunCmdAndGetOutput($"npm show {package.Name} version"); + string newVersion = currentVersion; + + if (includePreviews || (!switchToStable && currentVersion.Contains("-preview"))) + { + var mygetPackage = (await _myGetPackageListFinder.GetPackages()).Packages.FirstOrDefault(p => p.Id == package.Name); + if (mygetPackage != null) + { + newVersion = mygetPackage.Versions.Last(); + } + } + else + { + newVersion = CmdHelper.RunCmdAndGetOutput($"npm show {package.Name} version"); + } + - _fileVersionStorage[package.Name] = version; + _fileVersionStorage[package.Name] = newVersion; - return version; + return newVersion; } protected virtual List GetAbpPackagesFromPackageJson(JObject fileObject) { - var dependencyList = new [] { "dependencies", "devDependencies", "peerDependencies" }; + var dependencyList = new[] { "dependencies", "devDependencies", "peerDependencies" }; var abpPackages = new List(); foreach (var dependencyListName in dependencyList) diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/PackageSourceAdder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/PackageSourceAdder.cs new file mode 100644 index 0000000000..3e651b3bf1 --- /dev/null +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/PackageSourceAdder.cs @@ -0,0 +1,76 @@ +using System; +using System.IO; +using System.Xml; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Cli.ProjectModification +{ + public class PackageSourceAdder: ITransientDependency + { + public ILogger Logger { get; set; } + + public PackageSourceAdder() + { + Logger = NullLogger.Instance; + } + + public void Add(string sourceKey, string sourceValue) + { + var nugetConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), + "NuGet", "NuGet.Config"); + + if (!File.Exists(nugetConfigPath)) + { + return; + } + + var fileContent = File.ReadAllText(nugetConfigPath); + + if (fileContent.Contains($"\"{sourceValue}\"")) + { + return; + } + + Logger.LogInformation($"Adding \"{sourceValue}\" ({sourceKey}) to nuget sources..."); + + try + { + var doc = new XmlDocument() { PreserveWhitespace = true }; + + doc.Load(GenerateStreamFromString(fileContent)); + + var sourceNodes = doc.SelectNodes("/configuration/packageSources"); + + var newNode = doc.CreateElement("add"); + + var includeAttr = doc.CreateAttribute("key"); + includeAttr.Value = sourceKey; + newNode.Attributes.Append(includeAttr); + + var versionAttr = doc.CreateAttribute("value"); + versionAttr.Value = sourceValue; + newNode.Attributes.Append(versionAttr); + + sourceNodes?[0]?.AppendChild(newNode); + + File.WriteAllText(nugetConfigPath, doc.OuterXml); + } + catch + { + Logger.LogWarning($"Adding \"{sourceValue}\" ({sourceKey}) to nuget sources FAILED."); + } + } + + private static Stream GenerateStreamFromString(string s) + { + var stream = new MemoryStream(); + var writer = new StreamWriter(stream); + writer.Write(s); + writer.Flush(); + stream.Position = 0; + return stream; + } + } +} diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/PackageSourceSwitcher.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/PackageSourceSwitcher.cs new file mode 100644 index 0000000000..e860a68ba8 --- /dev/null +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/PackageSourceSwitcher.cs @@ -0,0 +1,86 @@ +using System; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Volo.Abp.Cli.Args; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Cli.ProjectModification +{ + public class PackageSourceSwitcher : ITransientDependency + { + private readonly PackageSourceAdder _packageSourceAdder; + private readonly NpmPackagesUpdater _npmPackagesUpdater; + private readonly VoloNugetPackagesVersionUpdater _nugetPackagesVersionUpdater; + + public ILogger Logger { get; set; } + + public PackageSourceSwitcher(PackageSourceAdder packageSourceAdder, + NpmPackagesUpdater npmPackagesUpdater, + VoloNugetPackagesVersionUpdater nugetPackagesVersionUpdater) + { + _packageSourceAdder = packageSourceAdder; + _npmPackagesUpdater = npmPackagesUpdater; + _nugetPackagesVersionUpdater = nugetPackagesVersionUpdater; + Logger = NullLogger.Instance; + } + + public async Task SwitchToPreview(CommandLineArgs commandLineArgs) + { + _packageSourceAdder.Add("ABP Nightly", "https://www.myget.org/F/abp-nightly/api/v3/index.json"); + + await _nugetPackagesVersionUpdater.UpdateSolutionAsync( + GetSolutionPath(commandLineArgs), + true); + + await _npmPackagesUpdater.Update( + Path.GetFileName(GetSolutionPath(commandLineArgs)), + true); + } + + public async Task SwitchToStable(CommandLineArgs commandLineArgs) + { + await _nugetPackagesVersionUpdater.UpdateSolutionAsync( + GetSolutionPath(commandLineArgs), + false, + true); + + await _npmPackagesUpdater.Update( + Path.GetFileName(GetSolutionPath(commandLineArgs)), + false, + true); + } + + + private string GetSolutionPath(CommandLineArgs commandLineArgs) + { + var solutionPath = commandLineArgs.Options.GetOrNull(Options.SolutionPath.Short, Options.SolutionPath.Long); + + if (solutionPath == null) + { + try + { + solutionPath = Directory.GetFiles(Directory.GetCurrentDirectory(), "*.sln").Single(); + } + catch (Exception) + { + Logger.LogError("There is no solution or more that one solution in current directory."); + throw; + } + } + + return solutionPath; + } + + public static class Options + { + public static class SolutionPath + { + public const string Short = "sp"; + public const string Long = "solution-path"; + } + } + } +} 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 d5756a4566..da8ded6a20 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 @@ -1,6 +1,7 @@ using System; using NuGet.Versioning; using System.IO; +using System.Linq; using System.Threading.Tasks; using System.Xml; using Volo.Abp.Cli.NuGet; @@ -13,37 +14,39 @@ namespace Volo.Abp.Cli.ProjectModification public class VoloNugetPackagesVersionUpdater : ITransientDependency { private readonly NuGetService _nuGetService; + private readonly MyGetPackageListFinder _myGetPackageListFinder; public ILogger Logger { get; set; } - public VoloNugetPackagesVersionUpdater(NuGetService nuGetService) + public VoloNugetPackagesVersionUpdater(NuGetService nuGetService, MyGetPackageListFinder myGetPackageListFinder) { _nuGetService = nuGetService; + _myGetPackageListFinder = myGetPackageListFinder; Logger = NullLogger.Instance; } - public async Task UpdateSolutionAsync(string solutionPath, bool includePreviews) + public async Task UpdateSolutionAsync(string solutionPath, bool includePreviews = false, bool switchToStable = false) { var projectPaths = ProjectFinder.GetProjectFiles(solutionPath); foreach (var filePath in projectPaths) { - await UpdateInternalAsync(filePath, includePreviews); + await UpdateInternalAsync(filePath, includePreviews, switchToStable); } } - public async Task UpdateProjectAsync(string projectPath, bool includePreviews) + public async Task UpdateProjectAsync(string projectPath, bool includePreviews = false, bool switchToStable = false) { - await UpdateInternalAsync(projectPath, includePreviews); + await UpdateInternalAsync(projectPath, includePreviews, switchToStable); } - protected virtual async Task UpdateInternalAsync(string projectPath, bool includePreviews) + protected virtual async Task UpdateInternalAsync(string projectPath, bool includePreviews = false, bool switchToStable = false) { var fileContent = File.ReadAllText(projectPath); - File.WriteAllText(projectPath, await UpdateVoloPackagesAsync(fileContent, includePreviews)); + File.WriteAllText(projectPath, await UpdateVoloPackagesAsync(fileContent, includePreviews, switchToStable)); } - private async Task UpdateVoloPackagesAsync(string content, bool includePreviews) + private async Task UpdateVoloPackagesAsync(string content, bool includePreviews = false, bool switchToStable = false) { string packageId = null; @@ -67,23 +70,44 @@ namespace Volo.Abp.Cli.ProjectModification continue; } - var versionAttribute = package.Attributes["Version"]; - packageId = package.Attributes["Include"].Value; - var packageVersion = SemanticVersion.Parse(versionAttribute.Value); + + var versionAttribute = package.Attributes["Version"]; + var currentVersion = versionAttribute.Value; + var packageVersion = SemanticVersion.Parse(currentVersion); Logger.LogDebug("Checking package: \"{0}\" - Current version: {1}", packageId, packageVersion); - var latestVersion = await _nuGetService.GetLatestVersionOrNullAsync(packageId, includePreviews); - if (latestVersion != null && packageVersion < latestVersion) + if (includePreviews || (currentVersion.Contains("-preview") && !switchToStable)) { - Logger.LogInformation("Updating package \"{0}\" from v{1} to v{2}.", packageId, packageVersion.ToString(), latestVersion.ToString()); - versionAttribute.Value = latestVersion.ToString(); + var latestVersion = (await _myGetPackageListFinder.GetPackages()).Packages + .FirstOrDefault(p => p.Id == packageId) + ?.Versions.LastOrDefault(); + + if (currentVersion != latestVersion) + { + Logger.LogInformation("Updating package \"{0}\" from v{1} to v{2}.", packageId, currentVersion, latestVersion); + versionAttribute.Value = latestVersion; + } + else + { + Logger.LogDebug("Package: \"{0}-v{1}\" is up to date.", packageId, currentVersion); + } } else { - Logger.LogDebug("Package: \"{0}-v{1}\" is up to date.", packageId, packageVersion); + var latestVersion = await _nuGetService.GetLatestVersionOrNullAsync(packageId); + + if (latestVersion != null && (currentVersion.Contains("-preview") || packageVersion < latestVersion)) + { + Logger.LogInformation("Updating package \"{0}\" from v{1} to v{2}.", packageId, packageVersion.ToString(), latestVersion.ToString()); + versionAttribute.Value = latestVersion.ToString(); + } + else + { + Logger.LogDebug("Package: \"{0}-v{1}\" is up to date.", packageId, packageVersion); + } } }