diff --git a/ECoreNetto.Tools.Tests/ECoreNetto.Tools.Tests.csproj b/ECoreNetto.Tools.Tests/ECoreNetto.Tools.Tests.csproj
index b0e7464..2578eee 100644
--- a/ECoreNetto.Tools.Tests/ECoreNetto.Tools.Tests.csproj
+++ b/ECoreNetto.Tools.Tests/ECoreNetto.Tools.Tests.csproj
@@ -46,4 +46,8 @@
+
+
+
+
diff --git a/ECoreNetto.Tools.Tests/Services/VersionCheckerTestFixture.cs b/ECoreNetto.Tools.Tests/Services/VersionCheckerTestFixture.cs
new file mode 100644
index 0000000..1b81db7
--- /dev/null
+++ b/ECoreNetto.Tools.Tests/Services/VersionCheckerTestFixture.cs
@@ -0,0 +1,74 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2017-2024 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace ECoreNetto.Tools.Tests.Services
+{
+ using System;
+ using System.Net.Http;
+ using System.Threading.Tasks;
+ using Microsoft.Extensions.Logging;
+ using NUnit.Framework;
+ using Serilog;
+ using Tools.Services;
+
+ [TestFixture]
+ public class VersionCheckerTestFixture
+ {
+ private VersionChecker versionChecker;
+
+ private ILoggerFactory? loggerFactory;
+
+ [OneTimeSetUp]
+ public void OneTimeSetUp()
+ {
+ Log.Logger = new LoggerConfiguration()
+ .MinimumLevel.Verbose()
+ .WriteTo.Console()
+ .CreateLogger();
+
+ this.loggerFactory = LoggerFactory.Create(builder =>
+ {
+ builder.AddSerilog();
+ });
+ }
+
+ [SetUp]
+ public void SetUp()
+ {
+ var httpClient = new HttpClient();
+ httpClient.Timeout = TimeSpan.FromSeconds(5);
+
+ this.versionChecker = new VersionChecker(httpClient, this.loggerFactory);
+ }
+
+ [Test]
+ public async Task Verify_that_Query_version_returns_result()
+ {
+ var result = await this.versionChecker.QueryLatestRelease();
+
+ Assert.That(result, Is.Not.Null);
+
+ Log.Logger.Information(result.TagName);
+ Log.Logger.Information(result.Body);
+ Log.Logger.Information(result.HtmlUrl);
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/ECoreNetto.Tools/Commands/MarkdownReportCommand.cs b/ECoreNetto.Tools/Commands/MarkdownReportCommand.cs
index 7429f2c..b27a067 100644
--- a/ECoreNetto.Tools/Commands/MarkdownReportCommand.cs
+++ b/ECoreNetto.Tools/Commands/MarkdownReportCommand.cs
@@ -25,7 +25,7 @@ namespace ECoreNetto.Tools.Commands
using System.IO;
using ECoreNetto.Reporting.Generators;
-
+
///
/// The that generates a Markdown report
///
diff --git a/ECoreNetto.Tools/Commands/ModelInspectionCommand.cs b/ECoreNetto.Tools/Commands/ModelInspectionCommand.cs
index c3ae55b..17c5016 100644
--- a/ECoreNetto.Tools/Commands/ModelInspectionCommand.cs
+++ b/ECoreNetto.Tools/Commands/ModelInspectionCommand.cs
@@ -25,7 +25,7 @@ namespace ECoreNetto.Tools.Commands
using System.IO;
using ECoreNetto.Reporting.Generators;
-
+
///
/// The that inspects an ECore model and generates
/// a text report
diff --git a/ECoreNetto.Tools/Commands/ReportHandler.cs b/ECoreNetto.Tools/Commands/ReportHandler.cs
index 6ac9a24..0bbc9af 100644
--- a/ECoreNetto.Tools/Commands/ReportHandler.cs
+++ b/ECoreNetto.Tools/Commands/ReportHandler.cs
@@ -20,8 +20,8 @@
namespace ECoreNetto.Tools.Commands
{
- using System.CommandLine.Invocation;
using System;
+ using System.CommandLine.Invocation;
using System.Diagnostics;
using System.IO;
using System.Threading;
diff --git a/ECoreNetto.Tools/ECoreNetto.Tools.csproj b/ECoreNetto.Tools/ECoreNetto.Tools.csproj
index fd6fd98..fb8cca9 100644
--- a/ECoreNetto.Tools/ECoreNetto.Tools.csproj
+++ b/ECoreNetto.Tools/ECoreNetto.Tools.csproj
@@ -45,6 +45,7 @@
+
diff --git a/ECoreNetto.Tools/Middlewares/VersionCheckerMiddleware.cs b/ECoreNetto.Tools/Middlewares/VersionCheckerMiddleware.cs
new file mode 100644
index 0000000..d4594f1
--- /dev/null
+++ b/ECoreNetto.Tools/Middlewares/VersionCheckerMiddleware.cs
@@ -0,0 +1,95 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2017-2024 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace ECoreNetto.Tools.Middlewares
+{
+ using System;
+ using System.CommandLine.Builder;
+ using System.CommandLine.Invocation;
+ using System.Net.Http;
+ using System.Reflection;
+ using System.Threading.Tasks;
+
+ using ECoreNetto.Tools.Services;
+
+ using Spectre.Console;
+
+ ///
+ /// A middleware that checks whether a newer version is available
+ ///
+ internal static class VersionCheckerMiddleware
+ {
+ ///
+ /// Configures the application to show check for a new version
+ ///
+ ///
+ /// A command line builder.
+ ///
+ ///
+ /// The same instance of .
+ ///
+ public static CommandLineBuilder UseVersionChecker(this CommandLineBuilder builder)
+ {
+ return builder.AddMiddleware(async (context, next) =>
+ {
+ var httpClient = new HttpClient();
+ httpClient.Timeout = TimeSpan.FromSeconds(2);
+ var versionChecker = new VersionChecker(httpClient);
+
+ try
+ {
+ var payload = await versionChecker.QueryLatestRelease();
+
+ if (payload != null)
+ {
+ var currentVersion = Assembly.GetExecutingAssembly().GetName().Version;
+ var publishedVersion = new Version(payload.TagName);
+
+ if (currentVersion < publishedVersion)
+ {
+ AnsiConsole.WriteLine("");
+ AnsiConsole.MarkupLine($"[Green] a newer version is available at {payload.HtmlUrl} [/]");
+ AnsiConsole.MarkupLine($"[Green] {payload.Body} [/]");
+ AnsiConsole.WriteLine("");
+ }
+ else
+ {
+ AnsiConsole.WriteLine("");
+ AnsiConsole.MarkupLine($"[Green] you are using the most recent version. [/]");
+ AnsiConsole.WriteLine("");
+ }
+ }
+
+ await next(context);
+ }
+ catch (TaskCanceledException ex)
+ {
+ AnsiConsole.WriteLine("");
+ AnsiConsole.MarkupLine($"[Red] Checking version at GitHub API timed out. [/]");
+ AnsiConsole.WriteLine("");
+ }
+ catch (Exception ex)
+ {
+ throw;
+ }
+ }, MiddlewareOrder.ExceptionHandler);
+ }
+ }
+}
\ No newline at end of file
diff --git a/ECoreNetto.Tools/Program.cs b/ECoreNetto.Tools/Program.cs
index 6d6e918..4cb16e3 100644
--- a/ECoreNetto.Tools/Program.cs
+++ b/ECoreNetto.Tools/Program.cs
@@ -38,6 +38,8 @@ namespace ECoreNetto.Tools
using Spectre.Console;
using ECoreNetto.Reporting.Generators;
+ using ECoreNetto.Tools.Services;
+ using Middlewares;
///
/// Main entry point for the command line application
@@ -65,6 +67,7 @@ public static int Main(string[] args)
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
+
})
.UseCommandHandler()
.UseCommandHandler()
@@ -101,7 +104,8 @@ private static CommandLineBuilder BuildCommandLine()
AnsiConsole.Markup($"[blue]{ResourceLoader.QueryLogo()}[/]");
}
));
- });
+ })
+ .UseVersionChecker();
}
///
diff --git a/ECoreNetto.Tools/Services/GitHubRelease.cs b/ECoreNetto.Tools/Services/GitHubRelease.cs
new file mode 100644
index 0000000..a46518a
--- /dev/null
+++ b/ECoreNetto.Tools/Services/GitHubRelease.cs
@@ -0,0 +1,48 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2017-2024 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace ECoreNetto.Tools.Services
+{
+ using System.Text.Json.Serialization;
+
+ ///
+ /// The class represents a response from the GitHb API
+ ///
+ public class GitHubRelease
+ {
+ ///
+ /// Gets or sets the url of the release page
+ ///
+ [JsonPropertyName("html_url")]
+ public string HtmlUrl { get; set; }
+
+ ///
+ /// Gets or sets the name of the tag
+ ///
+ [JsonPropertyName("tag_name")]
+ public string TagName{ get; set; }
+
+ ///
+ /// Gets or sets the description of the release
+ ///
+ [JsonPropertyName("body")]
+ public string Body { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/ECoreNetto.Tools/Services/VersionChecker.cs b/ECoreNetto.Tools/Services/VersionChecker.cs
new file mode 100644
index 0000000..6efe2b7
--- /dev/null
+++ b/ECoreNetto.Tools/Services/VersionChecker.cs
@@ -0,0 +1,98 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2017-2024 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace ECoreNetto.Tools.Services
+{
+ using System;
+ using System.Net.Http;
+ using System.Text.Json;
+ using System.Threading.Tasks;
+
+ using Microsoft.Extensions.Logging;
+ using Microsoft.Extensions.Logging.Abstractions;
+
+ ///
+ /// The purpose of the is to check whether a newer version is available
+ ///
+ public class VersionChecker
+ {
+ ///
+ /// The (injected) used to check the latest version that is available
+ ///
+ private readonly HttpClient httpClient;
+
+ ///
+ /// The used to log
+ ///
+ private readonly ILogger logger;
+
+ ///
+ /// Initializes a new instance of the
+ ///
+ ///
+ /// The (injected) used to check the latest version that is available
+ ///
+ ///
+ /// The (injected) used to set up logging
+ ///
+ public VersionChecker(HttpClient httpClient, ILoggerFactory loggerFactory = null)
+ {
+ this.httpClient = httpClient;
+ this.logger = loggerFactory == null ? NullLogger.Instance : loggerFactory.CreateLogger();
+ }
+
+ ///
+ /// Queries the latest version from the GitHub API
+ ///
+ ///
+ /// an instance of or null if not found or a connection
+ /// error occured
+ ///
+ public async Task QueryLatestRelease()
+ {
+ var requestUrl = "https://api.github.com/repos/STARIONGROUP/EcoreNetto/releases/latest";
+
+ try
+ {
+ this.httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("ECoreNetto.Tools");
+
+ var response = await this.httpClient.GetAsync(requestUrl);
+
+ if (response.IsSuccessStatusCode)
+ {
+ var jsonResponse = await response.Content.ReadAsStringAsync();
+ var release = JsonSerializer.Deserialize(jsonResponse);
+
+ return release;
+ }
+ }
+ catch (TaskCanceledException ex)
+ {
+ this.logger.LogWarning("Contacting the GitGub API at {url} timed out", requestUrl);
+ }
+ catch (Exception ex)
+ {
+ this.logger.LogError(ex, "");
+ }
+
+ return null;
+ }
+ }
+}
\ No newline at end of file