From 7f75312ea4ab9733008fa1982795a12c830c01d6 Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Wed, 4 Nov 2020 19:18:46 +0100 Subject: [PATCH 1/5] Improve API generation Now is non interactive by default and can be controlled with commandline arguments. Proper cancellation support to cancel generation. Cleaned up console output a bit --- src/ApiGenerator/ApiGenerator.csproj | 4 +- .../Generator/ApiEndpointFactory.cs | 8 +- src/ApiGenerator/Generator/ApiGenerator.cs | 30 ++--- .../Razor/ApiUrlsLookupsGenerator.cs | 5 +- .../Generator/Razor/DescriptorsGenerator.cs | 7 +- .../Generator/Razor/EnumsGenerator.cs | 5 +- .../HighLevelClientImplementationGenerator.cs | 7 +- .../HighLevelClientInterfaceGenerator.cs | 5 +- .../LowLevelClientImplementationGenerator.cs | 7 +- .../Razor/LowLevelClientInterfaceGenerator.cs | 5 +- .../Generator/Razor/RazorGeneratorBase.cs | 20 ++- .../Razor/RequestParametersGenerator.cs | 5 +- .../Generator/Razor/RequestsGenerator.cs | 7 +- src/ApiGenerator/Program.cs | 124 +++++++++++++++--- src/ApiGenerator/RestSpecDownloader.cs | 63 +++++---- 15 files changed, 203 insertions(+), 99 deletions(-) diff --git a/src/ApiGenerator/ApiGenerator.csproj b/src/ApiGenerator/ApiGenerator.csproj index a5f2254c0de..d78d51d3222 100644 --- a/src/ApiGenerator/ApiGenerator.csproj +++ b/src/ApiGenerator/ApiGenerator.csproj @@ -5,7 +5,7 @@ netcoreapp3.0 false - NU1701 + CS1591;NU1701 true @@ -15,6 +15,8 @@ + + diff --git a/src/ApiGenerator/Generator/ApiEndpointFactory.cs b/src/ApiGenerator/Generator/ApiEndpointFactory.cs index 68ef14918b2..a41f9192a13 100644 --- a/src/ApiGenerator/Generator/ApiEndpointFactory.cs +++ b/src/ApiGenerator/Generator/ApiEndpointFactory.cs @@ -56,7 +56,13 @@ private static void EnforceRequiredOnParts(string jsonFile, UrlInformation url) { var required = url.Paths.All(p => p.Path.Contains($"{{{part.Name}}}")); if (part.Required != required) - ApiGenerator.Warnings.Add($"{jsonFile} has part: {part.Name} listed as {part.Required} but should be {required}"); + { + var message = required + ? "is [b green] required [/] but appears in spec as [b red] optional [/]" + : "is [b green] optional [/] but marked as [b red] required [/] "; + // TODO submit PR to fix these, too noisy for now + //ApiGenerator.Warnings.Add($"[grey]{jsonFile}[/] part [b white] {part.Name} [/] {message}"); + } part.Required = required; } } diff --git a/src/ApiGenerator/Generator/ApiGenerator.cs b/src/ApiGenerator/Generator/ApiGenerator.cs index b318dc932c0..b527002b040 100644 --- a/src/ApiGenerator/Generator/ApiGenerator.cs +++ b/src/ApiGenerator/Generator/ApiGenerator.cs @@ -6,7 +6,8 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Threading.Tasks; + using System.Threading; + using System.Threading.Tasks; using ApiGenerator.Configuration; using ApiGenerator.Domain; using ApiGenerator.Domain.Specification; @@ -20,17 +21,17 @@ public class ApiGenerator { public static List Warnings { get; private set; } = new List(); - public static async Task Generate(string downloadBranch, bool lowLevelOnly, RestApiSpec spec) + public static async Task Generate(string downloadBranch, bool lowLevelOnly, RestApiSpec spec, CancellationToken token) { - static async Task DoGenerate(ICollection generators, RestApiSpec restApiSpec, bool highLevel) + static async Task DoGenerate(ICollection generators, RestApiSpec restApiSpec, bool highLevel, CancellationToken token) { - var pbarOpts = new ProgressBarOptions { BackgroundColor = ConsoleColor.DarkGray }; + var pbarOpts = new ProgressBarOptions { ProgressCharacter = '─', BackgroundColor = ConsoleColor.Yellow }; var message = $"Generating {(highLevel ? "high" : "low")} level code"; using var pbar = new ProgressBar(generators.Count, message, pbarOpts); foreach (var generator in generators) { pbar.Message = "Generating " + generator.Title; - await generator.Generate(restApiSpec, pbar); + await generator.Generate(restApiSpec, pbar, token); pbar.Tick("Generated " + generator.Title); } } @@ -55,23 +56,10 @@ static async Task DoGenerate(ICollection generators, RestApi new RequestsGenerator(), }; - await DoGenerate(lowLevelGenerators, spec, highLevel: false); + await DoGenerate(lowLevelGenerators, spec, highLevel: false, token); if (!lowLevelOnly) - await DoGenerate(highLevelGenerators, spec, highLevel: true); + await DoGenerate(highLevelGenerators, spec, highLevel: true, token); - // Check if there are any non-Stable endpoints present. - foreach (var endpoint in spec.Endpoints) - { - if (endpoint.Value.Stability != Stability.Stable) - Warnings.Add($"Endpoint {endpoint.Value.Name} is not marked as Stable ({endpoint.Value.Stability})"); - } - - if (Warnings.Count == 0) return; - - Console.ForegroundColor = ConsoleColor.Yellow; - foreach (var warning in Warnings.Distinct().OrderBy(w => w)) - Console.WriteLine(warning); - Console.ResetColor(); } public static RestApiSpec CreateRestApiSpecModel(string downloadBranch, params string[] folders) @@ -84,7 +72,7 @@ public static RestApiSpec CreateRestApiSpecModel(string downloadBranch, params s var endpoints = new SortedDictionary(); var seenFiles = new HashSet(); using (var pbar = new ProgressBar(directories.Count, $"Listing {directories.Count} directories", - new ProgressBarOptions { BackgroundColor = ConsoleColor.DarkGray, CollapseWhenFinished = false })) + new ProgressBarOptions { ProgressCharacter = '─', BackgroundColor = ConsoleColor.DarkGray, CollapseWhenFinished = false })) { var folderFiles = directories.Select(dir => Directory.GetFiles(dir) diff --git a/src/ApiGenerator/Generator/Razor/ApiUrlsLookupsGenerator.cs b/src/ApiGenerator/Generator/Razor/ApiUrlsLookupsGenerator.cs index e106bcd0185..c93d51373d1 100644 --- a/src/ApiGenerator/Generator/Razor/ApiUrlsLookupsGenerator.cs +++ b/src/ApiGenerator/Generator/Razor/ApiUrlsLookupsGenerator.cs @@ -2,6 +2,7 @@ // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information +using System.Threading; using System.Threading.Tasks; using ApiGenerator.Configuration; using ApiGenerator.Domain; @@ -13,12 +14,12 @@ public class ApiUrlsLookupsGenerator : RazorGeneratorBase { public override string Title => "NEST static url lookups"; - public override async Task Generate(RestApiSpec spec, ProgressBar progressBar) + public override async Task Generate(RestApiSpec spec, ProgressBar progressBar, CancellationToken token) { var view = ViewLocations.HighLevel("Requests", "ApiUrlsLookup.cshtml"); var target = GeneratorLocations.HighLevel("_Generated", "ApiUrlsLookup.generated.cs"); - await DoRazor(spec, view, target); + await DoRazor(spec, view, target, null, token); } } } diff --git a/src/ApiGenerator/Generator/Razor/DescriptorsGenerator.cs b/src/ApiGenerator/Generator/Razor/DescriptorsGenerator.cs index 2951709c957..2ae79e1d4d0 100644 --- a/src/ApiGenerator/Generator/Razor/DescriptorsGenerator.cs +++ b/src/ApiGenerator/Generator/Razor/DescriptorsGenerator.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; +using System.Threading; using System.Threading.Tasks; using ApiGenerator.Configuration; using ApiGenerator.Domain; @@ -15,7 +16,7 @@ public class DescriptorsGenerator : RazorGeneratorBase { public override string Title => "NEST descriptors"; - public override async Task Generate(RestApiSpec spec, ProgressBar progressBar) + public override async Task Generate(RestApiSpec spec, ProgressBar progressBar, CancellationToken token) { // Delete existing files foreach (var file in Directory.GetFiles(GeneratorLocations.NestFolder, "Descriptors.*.cs")) @@ -23,12 +24,12 @@ public override async Task Generate(RestApiSpec spec, ProgressBar progressBar) var view = ViewLocations.HighLevel("Descriptors", "RequestDescriptorBase.cshtml"); var target = GeneratorLocations.HighLevel("Descriptors.cs"); - await DoRazor(spec, view, target); + await DoRazor(spec, view, target, null, token); var dependantView = ViewLocations.HighLevel("Descriptors", "Descriptors.cshtml"); string Target(string id) => GeneratorLocations.HighLevel($"Descriptors.{id}.cs"); var namespaced = spec.EndpointsPerNamespaceHighLevel.ToList(); - await DoRazorDependantFiles(progressBar, namespaced, dependantView, kv => kv.Key, id => Target(id)); + await DoRazorDependantFiles(progressBar, namespaced, dependantView, kv => kv.Key, id => Target(id), token); } } } diff --git a/src/ApiGenerator/Generator/Razor/EnumsGenerator.cs b/src/ApiGenerator/Generator/Razor/EnumsGenerator.cs index 92060b49216..2004a2258f5 100644 --- a/src/ApiGenerator/Generator/Razor/EnumsGenerator.cs +++ b/src/ApiGenerator/Generator/Razor/EnumsGenerator.cs @@ -2,6 +2,7 @@ // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information +using System.Threading; using System.Threading.Tasks; using ApiGenerator.Configuration; using ApiGenerator.Domain; @@ -13,12 +14,12 @@ public class EnumsGenerator : RazorGeneratorBase { public override string Title => "Elasticsearch.Net enums"; - public override async Task Generate(RestApiSpec spec, ProgressBar progressBar) + public override async Task Generate(RestApiSpec spec, ProgressBar progressBar, CancellationToken token) { var view = ViewLocations.LowLevel("Enums.Generated.cshtml"); var target = GeneratorLocations.LowLevel("Api", "Enums.Generated.cs"); - await DoRazor(spec, view, target); + await DoRazor(spec, view, target, null, token); } } } diff --git a/src/ApiGenerator/Generator/Razor/HighLevelClientImplementationGenerator.cs b/src/ApiGenerator/Generator/Razor/HighLevelClientImplementationGenerator.cs index 74d487626d5..074411aae66 100644 --- a/src/ApiGenerator/Generator/Razor/HighLevelClientImplementationGenerator.cs +++ b/src/ApiGenerator/Generator/Razor/HighLevelClientImplementationGenerator.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; +using System.Threading; using System.Threading.Tasks; using ApiGenerator.Configuration; using ApiGenerator.Domain; @@ -16,7 +17,7 @@ public class HighLevelClientImplementationGenerator : RazorGeneratorBase { public override string Title => "NEST client implementation"; - public override async Task Generate(RestApiSpec spec, ProgressBar progressBar) + public override async Task Generate(RestApiSpec spec, ProgressBar progressBar, CancellationToken token) { // Delete existing files foreach (var file in Directory.GetFiles(GeneratorLocations.NestFolder, "ElasticClient.*.cs")) @@ -24,13 +25,13 @@ public override async Task Generate(RestApiSpec spec, ProgressBar progressBar) var view = ViewLocations.HighLevel("Client", "Implementation", "ElasticClient.cshtml"); var target = GeneratorLocations.HighLevel($"ElasticClient.{CsharpNames.RootNamespace}.cs"); - await DoRazor(spec, view, target); + await DoRazor(spec, view, target, null, token); string Target(string id) => GeneratorLocations.HighLevel($"ElasticClient.{id}.cs"); var namespaced = spec.EndpointsPerNamespaceHighLevel.Where(kv => kv.Key != CsharpNames.RootNamespace).ToList(); var dependantView = ViewLocations.HighLevel("Client", "Implementation", "ElasticClient.Namespace.cshtml"); - await DoRazorDependantFiles(progressBar, namespaced, dependantView, kv => kv.Key, id => Target(id)); + await DoRazorDependantFiles(progressBar, namespaced, dependantView, kv => kv.Key, id => Target(id), token); } } diff --git a/src/ApiGenerator/Generator/Razor/HighLevelClientInterfaceGenerator.cs b/src/ApiGenerator/Generator/Razor/HighLevelClientInterfaceGenerator.cs index ec3106ec9c7..d0eee31e07b 100644 --- a/src/ApiGenerator/Generator/Razor/HighLevelClientInterfaceGenerator.cs +++ b/src/ApiGenerator/Generator/Razor/HighLevelClientInterfaceGenerator.cs @@ -2,6 +2,7 @@ // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information +using System.Threading; using System.Threading.Tasks; using ApiGenerator.Configuration; using ApiGenerator.Domain; @@ -13,12 +14,12 @@ public class HighLevelClientInterfaceGenerator : RazorGeneratorBase { public override string Title => "NEST client interface"; - public override async Task Generate(RestApiSpec spec, ProgressBar progressBar) + public override async Task Generate(RestApiSpec spec, ProgressBar progressBar, CancellationToken token) { var view = ViewLocations.HighLevel("Client", "Interface", "IElasticClient.cshtml"); var target = GeneratorLocations.HighLevel("IElasticClient.Generated.cs"); - await DoRazor(spec, view, target); + await DoRazor(spec, view, target, null, token); } } } diff --git a/src/ApiGenerator/Generator/Razor/LowLevelClientImplementationGenerator.cs b/src/ApiGenerator/Generator/Razor/LowLevelClientImplementationGenerator.cs index 0e55d57ed62..36628100b99 100644 --- a/src/ApiGenerator/Generator/Razor/LowLevelClientImplementationGenerator.cs +++ b/src/ApiGenerator/Generator/Razor/LowLevelClientImplementationGenerator.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; +using System.Threading; using System.Threading.Tasks; using ApiGenerator.Configuration; using ApiGenerator.Domain; @@ -16,7 +17,7 @@ public class LowLevelClientImplementationGenerator : RazorGeneratorBase { public override string Title { get; } = "Elasticsearch.Net client implementation"; - public override async Task Generate(RestApiSpec spec, ProgressBar progressBar) + public override async Task Generate(RestApiSpec spec, ProgressBar progressBar, CancellationToken token) { // Delete existing files foreach (var file in Directory.GetFiles(GeneratorLocations.EsNetFolder, "ElasticLowLevelClient.*.cs")) @@ -24,12 +25,12 @@ public override async Task Generate(RestApiSpec spec, ProgressBar progressBar) var view = ViewLocations.LowLevel("Client", "Implementation", "ElasticLowLevelClient.cshtml"); var target = GeneratorLocations.LowLevel($"ElasticLowLevelClient.{CsharpNames.RootNamespace}.cs"); - await DoRazor(spec, view, target); + await DoRazor(spec, view, target, null, token); var namespaced = spec.EndpointsPerNamespaceLowLevel.Where(kv => kv.Key != CsharpNames.RootNamespace).ToList(); var namespacedView = ViewLocations.LowLevel("Client", "Implementation", "ElasticLowLevelClient.Namespace.cshtml"); await DoRazorDependantFiles(progressBar, namespaced, namespacedView, kv => kv.Key, - id => GeneratorLocations.LowLevel($"ElasticLowLevelClient.{id}.cs")); + id => GeneratorLocations.LowLevel($"ElasticLowLevelClient.{id}.cs"), token); } } } diff --git a/src/ApiGenerator/Generator/Razor/LowLevelClientInterfaceGenerator.cs b/src/ApiGenerator/Generator/Razor/LowLevelClientInterfaceGenerator.cs index 0b0b20c12f7..0833a0d1a3e 100644 --- a/src/ApiGenerator/Generator/Razor/LowLevelClientInterfaceGenerator.cs +++ b/src/ApiGenerator/Generator/Razor/LowLevelClientInterfaceGenerator.cs @@ -2,6 +2,7 @@ // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information +using System.Threading; using System.Threading.Tasks; using ApiGenerator.Configuration; using ApiGenerator.Domain; @@ -13,12 +14,12 @@ public class LowLevelClientInterfaceGenerator : RazorGeneratorBase { public override string Title { get; } = "Elasticsearch.Net client interface"; - public override async Task Generate(RestApiSpec spec, ProgressBar progressBar) + public override async Task Generate(RestApiSpec spec, ProgressBar progressBar, CancellationToken token) { var view = ViewLocations.LowLevel("Client", "Interface", "IElasticLowLevelClient.cshtml"); var target = GeneratorLocations.LowLevel("IElasticLowLevelClient.Generated.cs"); - await DoRazor(spec, view, target); + await DoRazor(spec, view, target, null, token); } } } diff --git a/src/ApiGenerator/Generator/Razor/RazorGeneratorBase.cs b/src/ApiGenerator/Generator/Razor/RazorGeneratorBase.cs index 7963b390c67..de95e0be0f2 100644 --- a/src/ApiGenerator/Generator/Razor/RazorGeneratorBase.cs +++ b/src/ApiGenerator/Generator/Razor/RazorGeneratorBase.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Threading; using System.Threading.Tasks; using ApiGenerator.Configuration; using ApiGenerator.Domain; @@ -24,12 +25,13 @@ public abstract class RazorGeneratorBase .UseMemoryCachingProvider() .Build(); - protected async Task DoRazor(TModel model, string viewLocation, string targetLocation, string cacheNameSuffix = null) + protected async Task DoRazor(TModel model, string viewLocation, string targetLocation, string cacheNameSuffix, CancellationToken token) { try { var name = GetType().Name + cacheNameSuffix; - var sourceFileContents = File.ReadAllText(viewLocation); + var sourceFileContents = await File.ReadAllTextAsync(viewLocation, token); + token.ThrowIfCancellationRequested(); var generated = await Engine.CompileRenderStringAsync(name, sourceFileContents, model); WriteFormattedCsharpFile(targetLocation, generated); } @@ -42,15 +44,21 @@ protected async Task DoRazor(TModel model, string viewLocation, string t protected async Task DoRazorDependantFiles( ProgressBar pbar, IReadOnlyCollection items, string viewLocation, - Func identifier, Func target) + Func identifier, Func target, + CancellationToken token + ) { - using (var c = pbar.Spawn(items.Count, "Generating namespaces", new ProgressBarOptions { ForegroundColor = ConsoleColor.Yellow })) + using (var c = pbar.Spawn(items.Count, "Generating namespaces", new ProgressBarOptions + { + ProgressCharacter = '─', + ForegroundColor = ConsoleColor.Yellow + })) { foreach (var item in items) { var id = identifier(item); var targetLocation = target(id); - await DoRazor(item, viewLocation, targetLocation, id); + await DoRazor(item, viewLocation, targetLocation, id, token); c.Tick($"{Title}: {id}"); } } @@ -65,6 +73,6 @@ protected static void WriteFormattedCsharpFile(string path, string contents) } public abstract string Title { get; } - public abstract Task Generate(RestApiSpec spec, ProgressBar progressBar); + public abstract Task Generate(RestApiSpec spec, ProgressBar progressBar, CancellationToken token); } } diff --git a/src/ApiGenerator/Generator/Razor/RequestParametersGenerator.cs b/src/ApiGenerator/Generator/Razor/RequestParametersGenerator.cs index 03b0267fe8d..64ce17cf491 100644 --- a/src/ApiGenerator/Generator/Razor/RequestParametersGenerator.cs +++ b/src/ApiGenerator/Generator/Razor/RequestParametersGenerator.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; +using System.Threading; using System.Threading.Tasks; using ApiGenerator.Configuration; using ApiGenerator.Domain; @@ -15,7 +16,7 @@ public class RequestParametersGenerator : RazorGeneratorBase { public override string Title { get; } = "Elasticsearch.Net request parameters"; - public override async Task Generate(RestApiSpec spec, ProgressBar progressBar) + public override async Task Generate(RestApiSpec spec, ProgressBar progressBar, CancellationToken token) { // Delete existing files foreach (var file in Directory.GetFiles(GeneratorLocations.EsNetFolder, "RequestParameters.*.cs")) @@ -25,7 +26,7 @@ public override async Task Generate(RestApiSpec spec, ProgressBar progressBar) string Target(string id) => GeneratorLocations.LowLevel("Api", "RequestParameters", $"RequestParameters.{id}.cs"); var namespaced = spec.EndpointsPerNamespaceLowLevel.ToList(); - await DoRazorDependantFiles(progressBar, namespaced, view, kv => kv.Key, id => Target(id)); + await DoRazorDependantFiles(progressBar, namespaced, view, kv => kv.Key, id => Target(id), token); } } } diff --git a/src/ApiGenerator/Generator/Razor/RequestsGenerator.cs b/src/ApiGenerator/Generator/Razor/RequestsGenerator.cs index 1f8bcd2f15f..3d8ff0e6e57 100644 --- a/src/ApiGenerator/Generator/Razor/RequestsGenerator.cs +++ b/src/ApiGenerator/Generator/Razor/RequestsGenerator.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; +using System.Threading; using System.Threading.Tasks; using ApiGenerator.Configuration; using ApiGenerator.Domain; @@ -15,7 +16,7 @@ public class RequestsGenerator : RazorGeneratorBase { public override string Title => "NEST requests"; - public override async Task Generate(RestApiSpec spec, ProgressBar progressBar) + public override async Task Generate(RestApiSpec spec, ProgressBar progressBar, CancellationToken token) { // Delete existing files foreach (var file in Directory.GetFiles(GeneratorLocations.NestFolder, "Requests.*.cs")) @@ -23,12 +24,12 @@ public override async Task Generate(RestApiSpec spec, ProgressBar progressBar) var view = ViewLocations.HighLevel("Requests", "PlainRequestBase.cshtml"); var target = GeneratorLocations.HighLevel("Requests.cs"); - await DoRazor(spec, view, target); + await DoRazor(spec, view, target, null, token); var dependantView = ViewLocations.HighLevel("Requests", "Requests.cshtml"); string Target(string id) => GeneratorLocations.HighLevel($"Requests.{id}.cs"); var namespaced = spec.EndpointsPerNamespaceHighLevel.ToList(); - await DoRazorDependantFiles(progressBar, namespaced, dependantView, kv => kv.Key, id => Target(id)); + await DoRazorDependantFiles(progressBar, namespaced, dependantView, kv => kv.Key, id => Target(id), token); } } } diff --git a/src/ApiGenerator/Program.cs b/src/ApiGenerator/Program.cs index 7925c5a8352..d5ba48a8515 100644 --- a/src/ApiGenerator/Program.cs +++ b/src/ApiGenerator/Program.cs @@ -5,22 +5,66 @@ using System; using System.IO; using System.Linq; +using System.Threading; using System.Threading.Tasks; using ApiGenerator.Configuration; +using Spectre.Console; + +#pragma warning disable 162 namespace ApiGenerator { public static class Program { - private static readonly string DownloadBranch = "master"; + private static bool Interactive { get; set; } = false; + + public static Style HeaderStyle { get; } = new Style(Color.White, Color.Chartreuse4); + + /// + /// A main function can also take which is hooked up to support termination (e.g CTRL+C) + /// + /// + /// + /// + /// + /// + /// + /// + /// + private static async Task Main(bool interactive = false, bool download = false, string branch = "master", bool includeHighLevel = false, bool skipGenerate = false, CancellationToken token = default, string[] args = null) + { + Interactive = interactive; + try + { + await Generate(download, branch, includeHighLevel, skipGenerate, token); + } + catch (OperationCanceledException) + { + AnsiConsole.WriteLine(); + AnsiConsole.Render(new Rule("[b white on orange4_1] Cancelled [/]").LeftAligned()); + AnsiConsole.WriteLine(); + return 1; + } + catch (Exception ex) + { + AnsiConsole.WriteLine(); + AnsiConsole.Render(new Rule("[b white on darkred] Exception [/]") + { + Alignment = Justify.Left, + }); + AnsiConsole.WriteLine(); + AnsiConsole.WriteException(ex); + return 1; + } + return 0; + } - // ReSharper disable once UnusedParameter.Local - private static async Task Main(string[] args) + private static async Task Generate(bool download, string branch, bool includeHighLevel, bool skipGenerate, CancellationToken token = default) { - var redownloadCoreSpecification = Ask("Download online rest specifications?", false); + var redownloadCoreSpecification = Ask("Download online rest specifications?", download); - var downloadBranch = DownloadBranch; - if (redownloadCoreSpecification) + var downloadBranch = branch; + if (Interactive && redownloadCoreSpecification) { Console.Write($"Branch to download specification from (default {downloadBranch}): "); var readBranch = Console.ReadLine()?.Trim(); @@ -34,33 +78,73 @@ private static async Task Main(string[] args) } if (string.IsNullOrEmpty(downloadBranch)) - downloadBranch = DownloadBranch; + downloadBranch = branch; + + var generateCode = Ask("Generate code from the specification files on disk?", !skipGenerate); + var lowLevelOnly = generateCode && Ask("Generate low level client only?", !includeHighLevel); - var generateCode = Ask("Generate code from the specification files on disk?", defaultAnswer: true); - var lowLevelOnly = generateCode && Ask("Generate low level client only?", defaultAnswer: false); + static string YesNo(bool value) => value ? "[bold green]Yes[/]" : "[grey]No[/]"; + var grid = new Grid() + .AddColumn(new GridColumn().PadRight(4)) + .AddColumn() + .AddRow("[b]Download specification[/]", $"{YesNo(download)}") + .AddRow("[b]Download branch[/]", $"{downloadBranch}") + .AddRow("[b]Generate code from specification[/]", $"{YesNo(generateCode)}") + .AddRow("[b]Include high level client[/]", $"{YesNo(!lowLevelOnly)}"); + + AnsiConsole.Render( + new Panel(grid) + .Header(new PanelHeader(" Elasticsearch .NET client API generator ", HeaderStyle, Justify.Left)) + ); if (redownloadCoreSpecification) - RestSpecDownloader.Download(downloadBranch); + { + AnsiConsole.Render(new Rule("[b white on chartreuse4] Downloading specification [/]").LeftAligned()); + await RestSpecDownloader.DownloadAsync(downloadBranch, token); + } + + if (!generateCode) return 0; - if (generateCode) + Console.WriteLine(); + AnsiConsole.Render(new Rule("[b white on chartreuse4] Loading specification [/]").LeftAligned()); + Console.WriteLine(); + + var spec = Generator.ApiGenerator.CreateRestApiSpecModel(downloadBranch, "Core", "XPack"); + if (!lowLevelOnly) { - var spec = Generator.ApiGenerator.CreateRestApiSpecModel(downloadBranch, "Core", "XPack"); - if (!lowLevelOnly) + foreach (var endpoint in spec.Endpoints.Select(e => e.Value.FileName)) { - foreach (var endpoint in spec.Endpoints.Select(e => e.Value.FileName)) - { - if (CodeConfiguration.IsNewHighLevelApi(endpoint) - && Ask($"Generate highlevel code for new api {endpoint}", false)) - CodeConfiguration.EnableHighLevelCodeGen.Add(endpoint); + if (CodeConfiguration.IsNewHighLevelApi(endpoint) + && Ask($"Generate highlevel code for new api {endpoint}", false)) + CodeConfiguration.EnableHighLevelCodeGen.Add(endpoint); - } } - await Generator.ApiGenerator.Generate(downloadBranch, lowLevelOnly, spec); } + + Console.WriteLine(); + AnsiConsole.Render(new Rule("[b white on chartreuse4] Generating code [/]").LeftAligned()); + Console.WriteLine(); + + await Generator.ApiGenerator.Generate(downloadBranch, lowLevelOnly, spec, token); + + var warnings = Generator.ApiGenerator.Warnings; + if (warnings.Count > 0) + { + Console.WriteLine(); + AnsiConsole.Render(new Rule("[b black on yellow] Specification warnings [/]").LeftAligned()); + Console.WriteLine(); + + foreach (var warning in warnings.Distinct().OrderBy(w => w)) + AnsiConsole.MarkupLine(" {0} [yellow] {1} [/] ", Emoji.Known.Warning, warning); + } + + return 0; } private static bool Ask(string question, bool defaultAnswer = true) { + if (!Interactive) return defaultAnswer; + var answer = "invalid"; var defaultResponse = defaultAnswer ? "y" : "n"; diff --git a/src/ApiGenerator/RestSpecDownloader.cs b/src/ApiGenerator/RestSpecDownloader.cs index 6f488d0acad..dad99fdeb1f 100644 --- a/src/ApiGenerator/RestSpecDownloader.cs +++ b/src/ApiGenerator/RestSpecDownloader.cs @@ -7,6 +7,9 @@ using System.IO; using System.Linq; using System.Net; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; using ApiGenerator.Configuration; using CsQuery; using ShellProgressBar; @@ -15,6 +18,7 @@ namespace ApiGenerator { public class RestSpecDownloader { + private readonly string _branch; private static readonly ProgressBarOptions MainProgressBarOptions = new ProgressBarOptions { BackgroundColor = ConsoleColor.DarkGray }; private static readonly Dictionary OnlineSpecifications = new Dictionary @@ -31,12 +35,14 @@ public class RestSpecDownloader BackgroundColor = ConsoleColor.DarkGray, }; - private RestSpecDownloader(string branch) + private RestSpecDownloader(string branch) => _branch = branch; + + private async Task DownloadAsync(CancellationToken token) { var specifications = (from kv in OnlineSpecifications - let url = kv.Value.Replace("{version}", branch) - select new Specification { FolderOnDisk = kv.Key, Branch = branch, GithubListingUrl = url }).ToList(); + let url = kv.Value.Replace("{version}", _branch) + select new Specification { FolderOnDisk = kv.Key, Branch = _branch, GithubListingUrl = url }).ToList(); using (var pbar = new ProgressBar(specifications.Count, "Downloading specifications", MainProgressBarOptions)) { @@ -48,62 +54,63 @@ private RestSpecDownloader(string branch) Directory.Delete(specFolderOnDisk, true); pbar.WriteLine($"Deleted target spec folder, before downloading new copy: {specFolderOnDisk}"); } - pbar.Message = $"Downloading rest-api-spec to {spec.FolderOnDisk} for branch {branch}"; - DownloadJsonDefinitions(spec, pbar); - pbar.Tick($"Downloaded rest-api-spec to {spec.FolderOnDisk} for branch {branch}"); + pbar.Message = $"Downloading rest-api-spec to {spec.FolderOnDisk} for branch {_branch}"; + await DownloadJsonDefinitions(spec, pbar, token); + pbar.Tick($"Downloaded rest-api-spec to {spec.FolderOnDisk} for branch {_branch}"); } } - File.WriteAllText(GeneratorLocations.LastDownloadedVersionFile, branch); + await File.WriteAllTextAsync(GeneratorLocations.LastDownloadedVersionFile, _branch, token); + } - public static RestSpecDownloader Download(string branch) => new RestSpecDownloader(branch); + public static Task DownloadAsync(string branch, CancellationToken token = default) => new RestSpecDownloader(branch).DownloadAsync(token); - private void DownloadJsonDefinitions(Specification spec, IProgressBar pbar) + private static readonly HttpClient Http = new HttpClient(); + private static async Task DownloadJsonDefinitions(Specification spec, IProgressBar pbar, CancellationToken token) { - using (var client = new WebClient()) - { - var html = client.DownloadString(spec.GithubListingUrl); - FindJsonFilesOnListing(spec, html, pbar); - } + var response = await Http.GetAsync(spec.GithubListingUrl, token); + var html = await response.Content.ReadAsStringAsync(); + + await FindJsonFilesOnListing(spec, html, pbar, token); } - private void FindJsonFilesOnListing(Specification spec, string html, IProgressBar pbar) + private static async Task FindJsonFilesOnListing(Specification spec, string html, IProgressBar pbar, CancellationToken token) { if (!Directory.Exists(GeneratorLocations.RestSpecificationFolder)) Directory.CreateDirectory(GeneratorLocations.RestSpecificationFolder); var dom = CQ.Create(html); - WriteToEndpointsFolder(spec.FolderOnDisk, "root.html", html); + await WriteToEndpointsFolder(spec.FolderOnDisk, "root.html", html, token); var endpoints = dom[".js-navigation-open"] .Select(s => s.InnerText) .Where(s => !string.IsNullOrEmpty(s) && s.EndsWith(".json")) .ToList(); - using (var subBar = pbar.Spawn(endpoints.Count, "fetching individual json files", SubProgressBarOptions)) - endpoints.ForEach(s => WriteEndpointFile(spec, s, subBar)); + using var subBar = pbar.Spawn(endpoints.Count, "fetching individual json files", SubProgressBarOptions); + foreach (var e in endpoints) + await WriteEndpointFile(spec, e, subBar, token); } - private void WriteEndpointFile(Specification spec, string s, IProgressBar pbar) + private static async Task WriteEndpointFile(Specification spec, string s, IProgressBar pbar, CancellationToken token) { var rawFile = spec.GithubDownloadUrl(s); - using (var client = new WebClient()) - { - var fileName = rawFile.Split('/').Last(); - var json = client.DownloadString(rawFile); - WriteToEndpointsFolder(spec.FolderOnDisk, fileName, json); - pbar.Tick($"Downloading {fileName}"); - } + var fileName = rawFile.Split('/').Last(); + + var response = await Http.GetAsync(rawFile, token); + var json = await response.Content.ReadAsStringAsync(); + await WriteToEndpointsFolder(spec.FolderOnDisk, fileName, json, token); + pbar.Tick($"Downloading {fileName}"); } - private void WriteToEndpointsFolder(string folder, string filename, string contents) + private static async Task WriteToEndpointsFolder(string folder, string filename, string contents, CancellationToken token) { var f = Path.Combine(GeneratorLocations.RestSpecificationFolder, folder); if (!Directory.Exists(f)) Directory.CreateDirectory(f); var target = Path.Combine(f, filename); - File.WriteAllText(target, contents); + await File.WriteAllTextAsync(target, contents, token); } private class Specification From 247bc59b51e782e8831e3d4d7186690d8faa96be Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Wed, 4 Nov 2020 19:26:36 +0100 Subject: [PATCH 2/5] clean up the output a tad more --- src/ApiGenerator/Program.cs | 4 ++++ src/ApiGenerator/RestSpecDownloader.cs | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/ApiGenerator/Program.cs b/src/ApiGenerator/Program.cs index d5ba48a8515..4acfe4f9012 100644 --- a/src/ApiGenerator/Program.cs +++ b/src/ApiGenerator/Program.cs @@ -92,14 +92,18 @@ private static async Task Generate(bool download, string branch, bool inclu .AddRow("[b]Generate code from specification[/]", $"{YesNo(generateCode)}") .AddRow("[b]Include high level client[/]", $"{YesNo(!lowLevelOnly)}"); + Console.WriteLine(); AnsiConsole.Render( new Panel(grid) .Header(new PanelHeader(" Elasticsearch .NET client API generator ", HeaderStyle, Justify.Left)) ); + Console.WriteLine(); if (redownloadCoreSpecification) { + Console.WriteLine(); AnsiConsole.Render(new Rule("[b white on chartreuse4] Downloading specification [/]").LeftAligned()); + Console.WriteLine(); await RestSpecDownloader.DownloadAsync(downloadBranch, token); } diff --git a/src/ApiGenerator/RestSpecDownloader.cs b/src/ApiGenerator/RestSpecDownloader.cs index dad99fdeb1f..0b192064a85 100644 --- a/src/ApiGenerator/RestSpecDownloader.cs +++ b/src/ApiGenerator/RestSpecDownloader.cs @@ -19,7 +19,11 @@ namespace ApiGenerator public class RestSpecDownloader { private readonly string _branch; - private static readonly ProgressBarOptions MainProgressBarOptions = new ProgressBarOptions { BackgroundColor = ConsoleColor.DarkGray }; + private static readonly ProgressBarOptions MainProgressBarOptions = new ProgressBarOptions + { + BackgroundColor = ConsoleColor.DarkGray, + ProgressCharacter = '─', + }; private static readonly Dictionary OnlineSpecifications = new Dictionary { From 18ef9095b247b4f321af263fa429bc4add5b1336 Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Wed, 4 Nov 2020 19:29:24 +0100 Subject: [PATCH 3/5] there is no need for root.html to be stored to disk and checked in --- src/ApiGenerator/RestSpecDownloader.cs | 2 - .../RestSpecification/Core/root.html | 3665 ------------- .../RestSpecification/XPack/root.html | 4767 ----------------- 3 files changed, 8434 deletions(-) delete mode 100644 src/ApiGenerator/RestSpecification/Core/root.html delete mode 100644 src/ApiGenerator/RestSpecification/XPack/root.html diff --git a/src/ApiGenerator/RestSpecDownloader.cs b/src/ApiGenerator/RestSpecDownloader.cs index 0b192064a85..b3d902ec23f 100644 --- a/src/ApiGenerator/RestSpecDownloader.cs +++ b/src/ApiGenerator/RestSpecDownloader.cs @@ -86,8 +86,6 @@ private static async Task FindJsonFilesOnListing(Specification spec, string html var dom = CQ.Create(html); - await WriteToEndpointsFolder(spec.FolderOnDisk, "root.html", html, token); - var endpoints = dom[".js-navigation-open"] .Select(s => s.InnerText) .Where(s => !string.IsNullOrEmpty(s) && s.EndsWith(".json")) diff --git a/src/ApiGenerator/RestSpecification/Core/root.html b/src/ApiGenerator/RestSpecification/Core/root.html deleted file mode 100644 index a3f9d447bf8..00000000000 --- a/src/ApiGenerator/RestSpecification/Core/root.html +++ /dev/null @@ -1,3665 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - elasticsearch/rest-api-spec/src/main/resources/rest-api-spec/api at master · elastic/elasticsearch · GitHub - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Skip to content - - - - - - - - -
- -
- - - - - -
- - - -
- - - - - - - - - -
-
-
- - - - - - - - - - - - - - - - - -
-
- - - -
- -
-
- - - master - - - - -
- - - -
-
-
- -
- - - - - -
- - - - - -
-
-

Latest commit

-
- -
-
 
-
-

Git stats

- -
-
-
-

Files

- - - - - Permalink - -
- - - Failed to load latest commit information. - -
-
-
-
Type
-
Name
-
Latest commit message
-
Commit time
-
-
- -
-
-
- -
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- -
- bulk.json -
- -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- -
- get.json -
- -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- -
- info.json -
- -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- -
- mget.json -
- -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- -
- ping.json -
- -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- -
- - -
- - - - - -
-
- -
-
- -
- - - - - - -
- - - You can’t perform that action at this time. -
- - - - - - - - - - - - - diff --git a/src/ApiGenerator/RestSpecification/XPack/root.html b/src/ApiGenerator/RestSpecification/XPack/root.html deleted file mode 100644 index a39b8b18ca8..00000000000 --- a/src/ApiGenerator/RestSpecification/XPack/root.html +++ /dev/null @@ -1,4767 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - elasticsearch/x-pack/plugin/src/test/resources/rest-api-spec/api at master · elastic/elasticsearch · GitHub - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Skip to content - - - - - - - - -
- -
- - - - - -
- - - -
- - - - - - - - - -
-
-
- - - - - - - - - - - - - - - - - -
-
- - - -
- -
-
- - - master - - - - -
- - - -
-
-
- -
- - - - - -
- - - - - -
-
-

Latest commit

-
- -
-
 
-
-

Git stats

- -
-
-
-

Files

- - - - - Permalink - -
- - - Failed to load latest commit information. - -
-
-
-
Type
-
Name
-
Latest commit message
-
Commit time
-
-
- -
-
-
- -
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- - -
- - - -
-
 
-
- -
-
 
-
- -
-
-
- -
- - -
- - - - - -
-
- -
-
- -
- - - - - - -
- - - You can’t perform that action at this time. -
- - - - - - - - - - - - - From 361e244c77be0aa11de59e87c146898e1b94a520 Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Fri, 6 Nov 2020 11:50:58 +0100 Subject: [PATCH 4/5] Use ref instead of branch --- .../Configuration/GeneratorLocations.cs | 2 +- src/ApiGenerator/Program.cs | 31 ++++++++++++------- src/ApiGenerator/RestSpecDownloader.cs | 30 +++++++++++++++--- 3 files changed, 46 insertions(+), 17 deletions(-) diff --git a/src/ApiGenerator/Configuration/GeneratorLocations.cs b/src/ApiGenerator/Configuration/GeneratorLocations.cs index f605b66f756..f8fe000f26a 100644 --- a/src/ApiGenerator/Configuration/GeneratorLocations.cs +++ b/src/ApiGenerator/Configuration/GeneratorLocations.cs @@ -11,7 +11,7 @@ public static class GeneratorLocations { // @formatter:off — disable formatter after this line public static string EsNetFolder { get; } = $@"{Root}../../src/Elasticsearch.Net/"; - public static string LastDownloadedVersionFile { get; } = Path.Combine(Root, "last_downloaded_version.txt"); + public static string LastDownloadedRef { get; } = Path.Combine(Root, "last_downloaded_version.txt"); public static string NestFolder { get; } = $@"{Root}../../src/Nest/"; public static string RestSpecificationFolder { get; } = $@"{Root}RestSpecification/"; diff --git a/src/ApiGenerator/Program.cs b/src/ApiGenerator/Program.cs index 4acfe4f9012..38981691fdd 100644 --- a/src/ApiGenerator/Program.cs +++ b/src/ApiGenerator/Program.cs @@ -3,6 +3,9 @@ // See the LICENSE file in the project root for more information using System; +using System.CommandLine; +using System.CommandLine.DragonFruit; +using System.CommandLine.Invocation; using System.IO; using System.Linq; using System.Threading; @@ -23,19 +26,25 @@ public static class Program /// /// A main function can also take which is hooked up to support termination (e.g CTRL+C) /// - /// - /// - /// - /// - /// + /// The stack's branch we are targeting the generation for + /// Run the generation interactively, this will ignore all flags + /// Whether to download the specs or use an already downloaded copy + /// Also generate the high level client (NEST) + /// Only download the specs, skip all code generation /// - /// /// - private static async Task Main(bool interactive = false, bool download = false, string branch = "master", bool includeHighLevel = false, bool skipGenerate = false, CancellationToken token = default, string[] args = null) + private static async Task Main( + string branch, bool interactive = false, bool download = false, bool includeHighLevel = false, bool skipGenerate = false + , CancellationToken token = default) { Interactive = interactive; try { + if (string.IsNullOrEmpty(branch)) + { + + throw new ArgumentException("--branch can not be null"); + } await Generate(download, branch, includeHighLevel, skipGenerate, token); } catch (OperationCanceledException) @@ -70,15 +79,15 @@ private static async Task Generate(bool download, string branch, bool inclu var readBranch = Console.ReadLine()?.Trim(); if (!string.IsNullOrEmpty(readBranch)) downloadBranch = readBranch; } - else + else if (string.IsNullOrEmpty(branch)) { // read last downloaded branch from file. - if (File.Exists(GeneratorLocations.LastDownloadedVersionFile)) - downloadBranch = File.ReadAllText(GeneratorLocations.LastDownloadedVersionFile); + if (File.Exists(GeneratorLocations.LastDownloadedRef)) + downloadBranch = File.ReadAllText(GeneratorLocations.LastDownloadedRef); } if (string.IsNullOrEmpty(downloadBranch)) - downloadBranch = branch; + throw new Exception($"--branch was not specified and could also not locate the checked in last reference: {GeneratorLocations.LastDownloadedRef}"); var generateCode = Ask("Generate code from the specification files on disk?", !skipGenerate); var lowLevelOnly = generateCode && Ask("Generate low level client only?", !includeHighLevel); diff --git a/src/ApiGenerator/RestSpecDownloader.cs b/src/ApiGenerator/RestSpecDownloader.cs index b3d902ec23f..289d20e2902 100644 --- a/src/ApiGenerator/RestSpecDownloader.cs +++ b/src/ApiGenerator/RestSpecDownloader.cs @@ -25,10 +25,11 @@ public class RestSpecDownloader ProgressCharacter = '─', }; + private static string CommitsUrl = "https://github.com/elastic/elasticsearch/commits/{branch}"; private static readonly Dictionary OnlineSpecifications = new Dictionary { - { "Core", "https://github.com/elastic/elasticsearch/tree/{version}/rest-api-spec/src/main/resources/rest-api-spec/api" }, - { "XPack", "https://github.com/elastic/elasticsearch/tree/{version}/x-pack/plugin/src/test/resources/rest-api-spec/api"} + { "Core", "https://github.com/elastic/elasticsearch/tree/{ref}/rest-api-spec/src/main/resources/rest-api-spec/api" }, + { "XPack", "https://github.com/elastic/elasticsearch/tree/{ref}/x-pack/plugin/src/test/resources/rest-api-spec/api"} }; private static readonly ProgressBarOptions SubProgressBarOptions = new ProgressBarOptions @@ -43,10 +44,12 @@ public class RestSpecDownloader private async Task DownloadAsync(CancellationToken token) { + var @ref = await ResolveLastRef(_branch, token); + var specifications = (from kv in OnlineSpecifications - let url = kv.Value.Replace("{version}", _branch) - select new Specification { FolderOnDisk = kv.Key, Branch = _branch, GithubListingUrl = url }).ToList(); + let url = kv.Value.Replace("{ref}", @ref) + select new Specification { FolderOnDisk = kv.Key, Branch = _branch, Ref = @ref, GithubListingUrl = url }).ToList(); using (var pbar = new ProgressBar(specifications.Count, "Downloading specifications", MainProgressBarOptions)) { @@ -64,12 +67,28 @@ private async Task DownloadAsync(CancellationToken token) } } - await File.WriteAllTextAsync(GeneratorLocations.LastDownloadedVersionFile, _branch, token); + await File.WriteAllTextAsync(GeneratorLocations.LastDownloadedRef, @ref, token); } public static Task DownloadAsync(string branch, CancellationToken token = default) => new RestSpecDownloader(branch).DownloadAsync(token); + private static async Task ResolveLastRef(string branch, CancellationToken token) + { + var response = await Http.GetAsync(CommitsUrl.Replace("{branch}", branch), token); + var html = await response.Content.ReadAsStringAsync(); + var dom = CQ.Create(html); + + var prefix = "/elastic/elasticsearch/commit/"; + var commit = dom["a.text-mono"] + .Select(s => s.GetAttribute("href")) + .Where(a => a.StartsWith(prefix)) + .Select(a => a.Replace(prefix, "")) + .FirstOrDefault() + ?? throw new Exception($"Can not locate the latest commit on branch: {branch}"); + return commit; + } + private static readonly HttpClient Http = new HttpClient(); private static async Task DownloadJsonDefinitions(Specification spec, IProgressBar pbar, CancellationToken token) { @@ -119,6 +138,7 @@ private class Specification { // ReSharper disable once UnusedAutoPropertyAccessor.Local public string Branch { get; set; } + public string Ref { get; set; } public string FolderOnDisk { get; set; } public string GithubListingUrl { get; set; } From 74591517c8c33b15de2d47db539a6a7bbd9506ee Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Mon, 9 Nov 2020 13:18:35 +0100 Subject: [PATCH 5/5] update error message --- src/ApiGenerator/Program.cs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/ApiGenerator/Program.cs b/src/ApiGenerator/Program.cs index 38981691fdd..3f0604915db 100644 --- a/src/ApiGenerator/Program.cs +++ b/src/ApiGenerator/Program.cs @@ -77,17 +77,12 @@ private static async Task Generate(bool download, string branch, bool inclu { Console.Write($"Branch to download specification from (default {downloadBranch}): "); var readBranch = Console.ReadLine()?.Trim(); - if (!string.IsNullOrEmpty(readBranch)) downloadBranch = readBranch; - } - else if (string.IsNullOrEmpty(branch)) - { - // read last downloaded branch from file. - if (File.Exists(GeneratorLocations.LastDownloadedRef)) - downloadBranch = File.ReadAllText(GeneratorLocations.LastDownloadedRef); + if (!string.IsNullOrEmpty(readBranch)) + downloadBranch = readBranch; } if (string.IsNullOrEmpty(downloadBranch)) - throw new Exception($"--branch was not specified and could also not locate the checked in last reference: {GeneratorLocations.LastDownloadedRef}"); + throw new Exception($"Branch to download from is null or empty"); var generateCode = Ask("Generate code from the specification files on disk?", !skipGenerate); var lowLevelOnly = generateCode && Ask("Generate low level client only?", !includeHighLevel);