Skip to content

Commit

Permalink
Merge pull request #249 from nblumhardt/app-update
Browse files Browse the repository at this point in the history
Basic app install and app update commands
  • Loading branch information
nblumhardt authored Aug 3, 2022
2 parents 4d5c0b0 + b50ad5c commit 2400c6a
Show file tree
Hide file tree
Showing 5 changed files with 237 additions and 1 deletion.
92 changes: 92 additions & 0 deletions src/SeqCli/Cli/Commands/App/InstallCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Copyright Datalust Pty Ltd and Contributors
//
// 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.

using System;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using SeqCli.Cli.Features;
using SeqCli.Config;
using SeqCli.Connection;
using SeqCli.Util;
using Serilog;

#nullable enable

namespace SeqCli.Cli.Commands.App;

[Command("app", "install", "Install an app package",
Example = "seqcli app install --package-id 'Seq.App.JsonArchive'")]
// ReSharper disable once UnusedType.Global
class InstallCommand : Command
{
readonly SeqConnectionFactory _connectionFactory;

readonly ConnectionFeature _connection;
readonly OutputFormatFeature _output;

string? _packageId, _version, _feedId;

public InstallCommand(SeqConnectionFactory connectionFactory, SeqCliConfig config)
{
_connectionFactory = connectionFactory ?? throw new ArgumentNullException(nameof(connectionFactory));

Options.Add(
"package-id=",
"The package id of the app to install",
packageId => _packageId = ArgumentString.Normalize(packageId));

Options.Add(
"version=",
"The package version to install; the default is to install the latest version",
version => _version = ArgumentString.Normalize(version));

Options.Add(
"feed-id=",
"The id of the NuGet feed to install the package from; may be omitted if only one feed is configured",
feedId => _feedId = ArgumentString.Normalize(feedId));

_connection = Enable<ConnectionFeature>();
_output = Enable(new OutputFormatFeature(config.Output));
}

protected override async Task<int> Run()
{
if (_packageId == null)
{
Log.Error("A `package-id` is required");
return 1;
}

var connection = _connectionFactory.Connect(_connection);

var feedId = _feedId;
if (feedId == null)
{
var feeds = await connection.Feeds.ListAsync();
if (feeds.Count != 1)
{
Log.Error("A `feed-id` is required unless the server has exactly one configured feed");
return 1;
}

feedId = feeds.Single().Id;
}

var app = await connection.Apps.InstallPackageAsync(feedId, _packageId, _version);
_output.WriteEntity(app);

return 0;
}
}
110 changes: 110 additions & 0 deletions src/SeqCli/Cli/Commands/App/UpdateCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// Copyright Datalust Pty Ltd and Contributors
//
// 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.

using System;
using System.Globalization;
using System.Threading.Tasks;
using SeqCli.Cli.Features;
using SeqCli.Config;
using SeqCli.Connection;
using SeqCli.Util;
using Serilog;

#nullable enable

namespace SeqCli.Cli.Commands.App;

[Command("app", "update", "Update an installed app package",
Example = "seqcli app update -n 'HTML Email'")]
// ReSharper disable once UnusedType.Global
class UpdateCommand : Command
{
readonly SeqConnectionFactory _connectionFactory;

readonly ConnectionFeature _connection;
readonly OutputFormatFeature _output;

string? _id, _name, _version;
bool _all, _force;

public UpdateCommand(SeqConnectionFactory connectionFactory, SeqCliConfig config)
{
_connectionFactory = connectionFactory ?? throw new ArgumentNullException(nameof(connectionFactory));

Options.Add(
"i=|id=",
"The id of a single installed app to update",
id => _id = ArgumentString.Normalize(id));

Options.Add(
"n=|name=",
"The name of the installed app to update",
name => _name = ArgumentString.Normalize(name));

Options.Add(
"all",
"Update all installed apps; not compatible with `-i` or `-n`",
_ => _all = true);

Options.Add(
"version=",
"The package version to update to; the default is to update to the latest version in the associated feed",
version => _version = ArgumentString.Normalize(version));


Options.Add(
"force",
"Update the app even if the target version is already installed",
_ => _force = true);

_connection = Enable<ConnectionFeature>();
_output = Enable(new OutputFormatFeature(config.Output));
}

protected override async Task<int> Run()
{
if (_all && (_id != null || _name != null) ||
_id != null && _name != null)
{
Log.Error("The `id`, `name`, and `all` options are mutually exclusive");
return 1;
}

if (_all && _version != null)
{
Log.Error("The `all` and `version` options are incompatible");
return 1;
}

if (!_all && _id == null && _name == null)
{
Log.Error("One of `id`, `name`, or `all` must be specified");
return 1;
}

var connection = _connectionFactory.Connect(_connection);

var apps = await connection.Apps.ListAsync();
foreach (var app in apps)
{
if (_all || app.Id == _id || _name != null && _name.Equals(app.Name, StringComparison.OrdinalIgnoreCase))
{
var updated = await connection.Apps.UpdatePackageAsync(app, _version, _force);
_output.WriteEntity(updated);
}
}

return 0;
}
}
9 changes: 9 additions & 0 deletions src/SeqCli/Cli/Commands/HelpCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,17 @@ protected override Task<int> Run(string[] unrecognized)
var subCommandHelp = subCommand == null ? "" : " " + subCommand;
Console.WriteLine(name + " " + cmd.Metadata.Name + subCommandHelp + argHelp);
Console.WriteLine();

Console.WriteLine(cmd.Metadata.HelpText);
Console.WriteLine();

if (cmd.Metadata.Example != null)
{
Console.WriteLine("Example:");
Console.WriteLine($" {cmd.Metadata.Example}");
Console.WriteLine();
}

cmd.Value.Value.PrintUsage();
return Task.FromResult(0);
}
Expand Down
25 changes: 25 additions & 0 deletions test/SeqCli.EndToEnd/App/AppBasicsTestCase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System.Threading.Tasks;
using Seq.Api;
using SeqCli.EndToEnd.Support;
using Serilog;
using Xunit;

namespace SeqCli.EndToEnd.App;

// ReSharper disable once UnusedType.Global
public class AppBasicsTestCase: ICliTestCase
{
public Task ExecuteAsync(SeqConnection connection, ILogger logger, CliCommandRunner runner)
{
var exit = runner.Exec("feed list", "-n nuget.org");
Assert.Equal(0, exit);

exit = runner.Exec("app install", "--package-id Seq.App.EmailPlus");
Assert.Equal(0, exit);

exit = runner.Exec("app update", "--all");
Assert.Equal(0, exit);

return Task.CompletedTask;
}
}
2 changes: 1 addition & 1 deletion test/SeqCli.EndToEnd/Feed/FeedBasicsTestCase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ static void AssertExistence(CliCommandRunner runner, string feedName, bool exist
var exit = runner.Exec("feed list", $"-n {feedName}");
Assert.Equal(0, exit);

var output = runner.LastRunProcess.Output;
var output = runner.LastRunProcess!.Output;

if (exists)
{
Expand Down

0 comments on commit 2400c6a

Please sign in to comment.