feat: New `create-config` subcommand

Allows the user to create a starter YAML config
recyclarr
Robert Dailey 3 years ago
parent 48aeb2d7c5
commit 2eefdc0325

@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Added
- New `create-config` subcommand to create a starter YAML config file
## [1.1.0] - 2021-04-18
### Added

@ -61,21 +61,28 @@ too. Run this from the directory where you want `trash` to be installed.
## Getting Started
> **TL;DR**: Run `trash [sonarr|radarr] --help` for help with available command line options. Visit
> [the wiki](https://github.com/rcdailey/trash-updater/wiki) for in-depth documentation about the
> command line, configuration, and other topics.
Trash Updater requires a YML configuration file in order to work. Run the steps below if you want to
get started with minimal configuration file template.
The `trash` executable provides one subcommand per distinct service. This means, for example, you
can run `trash sonarr` and `trash radarr`. When you run these subcommands, the relevant service
configuration is read from the YAML files.
- Run `trash create-config` to create a starter `trash.yml` file in the same directory as the
executable. You can also use `--config` to
- Open the generated YAML file from the previous step. At a minimum you must update the `base_url`
and `api_key` settings for each service that you want to use.
- Run `trash sonarr` and/or `trash.radarr` as needed to update those instances.
That's all you need to do on the command line to get the program to parse guides and push settings
to the respective service. Most of the documentation will be for the YAML configuration, which is
what drives the behavior of the program.
The last step above will do a "basic" sync from the guides to Sonarr and/or Radarr. The starter YAML
config is very minimal. See the next section for further reading and links to the wiki for
additional topics and more advanced customization.
Lastly, each subcommand supports printing help on the command line. Simply run `trash --help` for
the main help output and a list of subcommands. You can then see the help for each subcommand by
running `trash [subcommand] --help`, where `[subcommand]` is one of those subcommands (e.g.
`sonarr`)
### Read the Documentation
Main documentation is located in the wiki. Links provided below for some main topics.
Main documentation is located in [the wiki](https://github.com/rcdailey/trash-updater/wiki). Links
provided below for some main topics.
- [Command Line Reference](../../wiki/Command-Line-Reference)
- [Configuration Reference](../../wiki/Configuration-Reference)

@ -0,0 +1,46 @@
using System.IO.Abstractions;
using System.Threading.Tasks;
using CliFx.Infrastructure;
using NSubstitute;
using NUnit.Framework;
using Serilog;
using Trash.CreateConfig;
// ReSharper disable MethodHasAsyncOverload
namespace Trash.Tests.CreateConfig
{
[TestFixture]
[Parallelizable(ParallelScope.All)]
public class CreateConfigCommandTest
{
[Test]
public async Task CreateConfig_DefaultPath_FileIsCreated()
{
var logger = Substitute.For<ILogger>();
var filesystem = Substitute.For<IFileSystem>();
var cmd = new CreateConfigCommand(logger, filesystem);
await cmd.ExecuteAsync(Substitute.For<IConsole>());
filesystem.File.Received().Exists(Arg.Is<string>(s => s.EndsWith("trash.yml")));
filesystem.File.Received().WriteAllText(Arg.Is<string>(s => s.EndsWith("trash.yml")), Arg.Any<string>());
}
[Test]
public async Task CreateConfig_SpecifyPath_FileIsCreated()
{
var logger = Substitute.For<ILogger>();
var filesystem = Substitute.For<IFileSystem>();
var cmd = new CreateConfigCommand(logger, filesystem)
{
Path = "some/other/path.yml"
};
await cmd.ExecuteAsync(Substitute.For<IConsole>());
filesystem.File.Received().Exists(Arg.Is("some/other/path.yml"));
filesystem.File.Received().WriteAllText(Arg.Is("some/other/path.yml"), Arg.Any<string>());
}
}
}

@ -0,0 +1,19 @@
using FluentAssertions.Formatting;
using Trash.Sonarr.ReleaseProfile;
namespace Trash.Tests.ValueFormatters
{
public class ProfileDataValueFormatter : IValueFormatter
{
public bool CanHandle(object value)
{
return value is ProfileData;
}
public string Format(object value, FormattingContext context, FormatChild formatChild)
{
var profileData = (ProfileData) value;
return $"{profileData.Ignored}";
}
}
}

@ -27,6 +27,8 @@ namespace Trash.Command
Log = logger;
}
public static string DefaultConfigPath { get; } = Path.Join(AppContext.BaseDirectory, "trash.yml");
protected ILogger Log { get; }
[CommandOption("preview", 'p', Description =
@ -40,8 +42,7 @@ namespace Trash.Command
[CommandOption("config", 'c', Description =
"One or more YAML config files to use. All configs will be used and settings are additive. " +
"If not specified, the script will look for `trash.yml` in the same directory as the executable.")]
public List<string> Config { get; [UsedImplicitly] set; } =
new() {Path.Join(AppContext.BaseDirectory, "trash.yml")};
public List<string> Config { get; [UsedImplicitly] set; } = new() {DefaultConfigPath};
public async ValueTask ExecuteAsync(IConsole console)
{

@ -1,9 +1,9 @@
using System.IO.Abstractions;
using System.Reflection;
using Autofac;
using CliFx;
using Serilog;
using Serilog.Core;
using Trash.Command;
using Trash.Config;
using Trash.Radarr.Api;
using Trash.Radarr.QualityDefinition;
@ -16,42 +16,6 @@ namespace Trash
{
public static class CompositionRoot
{
// private static void SetupMediator(ContainerBuilder builder)
// {
// builder
// .RegisterType<Mediator>()
// .As<IMediator>()
// .InstancePerLifetimeScope();
//
// builder.Register<ServiceFactory>(context =>
// {
// var c = context.Resolve<IComponentContext>();
// return t => c.Resolve(t);
// });
//
// builder.RegisterAssemblyTypes(typeof(CompositionRoot).GetTypeInfo().Assembly).AsImplementedInterfaces();
// }
// private static void RegisterConfiguration<T>(ContainerBuilder builder)
// where T : BaseConfiguration
// {
//
// builder.Register(ctx =>
// {
// var selector = ctx.Resolve<IConfigurationProvider<T>>();
// if (selector.ActiveConfiguration == null)
// {
// // If this exception is thrown, that means that a BaseCommand subclass has not implemented the
// // appropriate logic to set the active configuration via an IConfigurationSelector.
// throw new InvalidOperationException("No valid configuration has been selected");
// }
//
// return selector.ActiveConfiguration;
// })
// .As<BaseConfiguration>()
// .AsSelf();
// }
private static void SetupLogging(ContainerBuilder builder)
{
builder.RegisterType<LoggingLevelSwitch>().SingleInstance();
@ -101,9 +65,9 @@ namespace Trash
.As(typeof(IConfigurationProvider<>))
.SingleInstance();
// Register all types deriving from BaseCommand. These are all of our supported subcommands.
// Register all types deriving from CliFx's ICommand. These are all of our supported subcommands.
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
.Where(t => t.IsAssignableTo(typeof(IBaseCommand)));
.Where(t => t.IsAssignableTo(typeof(ICommand)));
SetupLogging(builder);
SonarrRegistrations(builder);

@ -0,0 +1,50 @@
using System.IO.Abstractions;
using System.Threading.Tasks;
using CliFx;
using CliFx.Attributes;
using CliFx.Exceptions;
using CliFx.Infrastructure;
using Common;
using JetBrains.Annotations;
using Serilog;
using Trash.Command;
namespace Trash.CreateConfig
{
[Command("create-config", Description = "Create a starter YAML configuration file")]
[UsedImplicitly]
public class CreateConfigCommand : ICommand
{
private readonly IFileSystem _fileSystem;
public CreateConfigCommand(ILogger logger, IFileSystem fileSystem)
{
Log = logger;
_fileSystem = fileSystem;
}
private ILogger Log { get; }
[CommandOption("path", 'p', Description =
"Path where the new YAML file should be created. Must include the filename (e.g. path/to/config.yml). " +
"File must not already exist. If not specified, uses the default path of `trash.yml` right next to the " +
"executable.")]
public string Path { get; [UsedImplicitly] set; } = BaseCommand.DefaultConfigPath;
public ValueTask ExecuteAsync(IConsole console)
{
var reader = new ResourceDataReader(typeof(Program));
var ymlData = reader.ReadData("trash-config-template.yml");
if (_fileSystem.File.Exists(Path))
{
throw new CommandException($"The file {Path} already exists. Please choose another path or " +
"delete/move the existing file and run this command again.");
}
_fileSystem.File.WriteAllText(Path, ymlData);
Log.Information("Created configuration at: {Path}", Path);
return default;
}
}
}

@ -21,4 +21,8 @@
<ItemGroup>
<ProjectReference Include="..\Common\Common.csproj" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="trash-config-template.yml" />
</ItemGroup>
</Project>

@ -0,0 +1,33 @@
# A starter config to use with Trash Updater. Most values are set to "reasonable defaults".
# Update the values below as needed for your instance. You will be required to update the
# API Key and URL for each instance you want to use.
#
# Many optional settings have been omitted to keep this template simple.
#
# For more details on the configuration, see the Configuration Reference on the wiki here:
# https://github.com/rcdailey/trash-updater/wiki/Configuration-Reference
# Configuration specific to Sonarr
sonarr:
# Set the URL/API Key to your actual instance
- base_url: http://localhost:8989
api_key: f7e74ba6c80046e39e076a27af5a8444
# Quality definitions from the guide to sync to Sonarr. Choice: anime, series, hybrid
quality_definition: hybrid
# Release profiles from the guide to sync to Sonarr. Types: anime, series
# You can optionally add tags and make negative scores strictly ignored
release_profiles:
- type: anime
- type: series
# Configuration specific to Radarr.
radarr:
# Set the URL/API Key to your actual instance
- base_url: http://localhost:7878
api_key: bf99da49d0b0488ea34e4464aa63a0e5
# Which quality definition in the guide to sync to Radarr. Only choice right now is 'movie'
quality_definition:
type: movie
Loading…
Cancel
Save