diff --git a/source/Octo/Commands/ExportCommand.cs b/source/Octo/Commands/ExportCommand.cs index 51e77a4c9..ddc36e7c7 100644 --- a/source/Octo/Commands/ExportCommand.cs +++ b/source/Octo/Commands/ExportCommand.cs @@ -20,13 +20,14 @@ public ExportCommand(IExporterLocator exporterLocator, IOctopusFileSystem fileSy this.exporterLocator = exporterLocator; var options = Options.For("Export"); - options.Add("type=", "The type to export", v => Type = v); + options.Add("type=", "The type to export, either Project, Release or Variables", v => Type = v); options.Add("filePath=", "The full path and name of the export file", v => FilePath = v); - options.Add("project=", "[Optional] Name of the project", v => Project = v); - options.Add("name=", "[Optional] Name of the item to export", v => Name = v); - options.Add("releaseVersion=", "[Optional] The version number, or range of version numbers to export", v => ReleaseVersion = v); + options.Add("name=", "Name of the item to export (only for --type=Project)", v => Name = v); + options.Add("project=", "Name of the project (only for --type=Release or --type=Variables)", v => Project = v); + options.Add("releaseVersion=", "The version number, or range of version numbers to export (only for --type=Release)", v => ReleaseVersion = v); } + public string Type { get; set; } public string FilePath { get; set; } public string Project { get; set; } @@ -44,7 +45,7 @@ protected override Task Execute() throw new CommandException("Error: Unrecognized exporter '" + Type + "'"); Log.Debug("Beginning the export"); - return exporter.Export(string.Format("FilePath={0}", FilePath), string.Format("Project={0}", Project), string.Format("Name={0}", Name), string.Format("ReleaseVersion={0}", ReleaseVersion)); + return exporter.Export($"FilePath={FilePath}", $"Project={Project}", $"Name={Name}", $"ReleaseVersion={ReleaseVersion}"); } } } \ No newline at end of file diff --git a/source/Octo/Commands/ImportCommand.cs b/source/Octo/Commands/ImportCommand.cs index ad582e2a6..c89e655e0 100644 --- a/source/Octo/Commands/ImportCommand.cs +++ b/source/Octo/Commands/ImportCommand.cs @@ -19,9 +19,9 @@ public ImportCommand(IImporterLocator importerLocator, IOctopusFileSystem fileSy this.importerLocator = importerLocator; var options = Options.For("Import"); - options.Add("type=", "The Octopus object type to import", v => Type = v); + options.Add("type=", "The Octopus object type to import, either Project, Release or Variables", v => Type = v); options.Add("filePath=", "The full path and name of the exported file", v => FilePath = v); - options.Add("project=", "[Optional] The name of the project", v => Project = v); + options.Add("project=", "The name of the project (only for --type=Release or --type=Variables)", v => Project = v); options.Add("dryRun", "[Optional] Perform a dry run of the import", v => DryRun = true); } @@ -41,11 +41,11 @@ protected override async Task Execute() throw new CommandException("Error: Unrecognized importer '" + Type + "'"); Log.Debug("Validating the import"); - var validationResult = await importer.Validate(string.Format("FilePath={0}", FilePath), string.Format("Project={0}", Project)).ConfigureAwait(false); + var validationResult = await importer.Validate($"FilePath={FilePath}", $"Project={Project}").ConfigureAwait(false); if (validationResult && !DryRun) { Log.Debug("Beginning the import"); - await importer.Import(string.Format("FilePath={0}", FilePath), string.Format("Project={0}", Project)).ConfigureAwait(false); + await importer.Import($"FilePath={FilePath}", $"Project={Project}").ConfigureAwait(false); } } } diff --git a/source/Octo/Exporters/ExporterAttribute.cs b/source/Octo/Exporters/ExporterAttribute.cs index c77b55afa..bae202906 100644 --- a/source/Octo/Exporters/ExporterAttribute.cs +++ b/source/Octo/Exporters/ExporterAttribute.cs @@ -5,15 +5,12 @@ namespace Octopus.Cli.Exporters [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] public class ExporterAttribute : Attribute, IExporterMetadata { - public ExporterAttribute(string name, string entityType) + public ExporterAttribute(string name) { Name = name; - EntityType = entityType; } - - public string EntityType { get; set; } + public string Name { get; set; } - public string Description { get; set; } } } \ No newline at end of file diff --git a/source/Octo/Exporters/ExporterLocator.cs b/source/Octo/Exporters/ExporterLocator.cs index a178aebe5..a98ccba7c 100644 --- a/source/Octo/Exporters/ExporterLocator.cs +++ b/source/Octo/Exporters/ExporterLocator.cs @@ -1,5 +1,4 @@ -using System; -using System.Linq; +using System.Linq; using System.Reflection; using Autofac; using Serilog; diff --git a/source/Octo/Exporters/IExporterMetadata.cs b/source/Octo/Exporters/IExporterMetadata.cs index e8a4c83d8..de7e72687 100644 --- a/source/Octo/Exporters/IExporterMetadata.cs +++ b/source/Octo/Exporters/IExporterMetadata.cs @@ -5,6 +5,5 @@ namespace Octopus.Cli.Exporters public interface IExporterMetadata { string Name { get; set; } - string Description { get; set; } } } \ No newline at end of file diff --git a/source/Octo/Commands/ProjectExport.cs b/source/Octo/Exporters/ProjectExport.cs similarity index 96% rename from source/Octo/Commands/ProjectExport.cs rename to source/Octo/Exporters/ProjectExport.cs index 9493cefd3..43a400b0d 100644 --- a/source/Octo/Commands/ProjectExport.cs +++ b/source/Octo/Exporters/ProjectExport.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using Octopus.Client.Model; -namespace Octopus.Cli.Commands +namespace Octopus.Cli.Exporters { public class ProjectExport { diff --git a/source/Octo/Exporters/ProjectExporter.cs b/source/Octo/Exporters/ProjectExporter.cs index 713d2dcb6..be64d5ef5 100644 --- a/source/Octo/Exporters/ProjectExporter.cs +++ b/source/Octo/Exporters/ProjectExporter.cs @@ -13,7 +13,7 @@ namespace Octopus.Cli.Exporters { - [Exporter("project", "ProjectWithDependencies", Description = "Exports a project as JSON to a file")] + [Exporter("project")] public class ProjectExporter : BaseExporter { readonly ActionTemplateRepository actionTemplateRepository; @@ -164,7 +164,7 @@ protected override async Task Export(Dictionary parameters) ExportedAt = DateTime.Now, OctopusVersion = Repository.Client.RootDocument.Version, Type = typeof (ProjectExporter).GetAttributeValue((ExporterAttribute ea) => ea.Name), - ContainerType = typeof (ProjectExporter).GetAttributeValue((ExporterAttribute ea) => ea.EntityType) + ContainerType = "ProjectWithDependencies" }; FileSystemExporter.Export(FilePath, metadata, export); } diff --git a/source/Octo/Exporters/ReleaseExporter.cs b/source/Octo/Exporters/ReleaseExporter.cs index 2ffd05b21..7a2e135e1 100644 --- a/source/Octo/Exporters/ReleaseExporter.cs +++ b/source/Octo/Exporters/ReleaseExporter.cs @@ -11,7 +11,7 @@ namespace Octopus.Cli.Exporters { - [Exporter("release", "List", Description = "Exports either a single release, or multiple releases")] + [Exporter("release")] public class ReleaseExporter : BaseExporter { public ReleaseExporter(IOctopusAsyncRepository repository, IOctopusFileSystem fileSystem, ILogger log) : @@ -92,7 +92,7 @@ await releases.Paginate(Repository, page => ExportedAt = DateTime.Now, OctopusVersion = Repository.Client.RootDocument.Version, Type = typeof (ReleaseExporter).GetAttributeValue((ExporterAttribute ea) => ea.Name), - ContainerType = typeof (ReleaseExporter).GetAttributeValue((ExporterAttribute ea) => ea.EntityType) + ContainerType = "List" }; FileSystemExporter.Export(FilePath, metadata, releasesToExport); } diff --git a/source/Octo/Exporters/VariablesExporter.cs b/source/Octo/Exporters/VariablesExporter.cs new file mode 100644 index 000000000..a26c18e3a --- /dev/null +++ b/source/Octo/Exporters/VariablesExporter.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Serilog; +using Octopus.Cli.Commands; +using Octopus.Cli.Extensions; +using Octopus.Cli.Infrastructure; +using Octopus.Cli.Repositories; +using Octopus.Cli.Util; +using Octopus.Client; +using Octopus.Client.Model; + +namespace Octopus.Cli.Exporters +{ + [Exporter("variables")] + public class VariablesExporter : BaseExporter + { + + public VariablesExporter(IOctopusAsyncRepository repository, IOctopusFileSystem fileSystem, ILogger log) + : base(repository, fileSystem, log) + { + } + + protected override async Task Export(Dictionary parameters) + { + var projectName = parameters["Project"]; + if (string.IsNullOrWhiteSpace(projectName)) + throw new CommandException("Please specify the name of the project to export using the parameter: --project=XYZ"); + + + Log.Debug("Finding project: {Project:l}", projectName); + var project = await Repository.Projects.FindByName(projectName).ConfigureAwait(false); + if (project == null) + throw new CouldNotFindException("a project named", projectName); + + Log.Debug("Finding variable set for project"); + var variables = await Repository.VariableSets.Get(project.VariableSetId).ConfigureAwait(false); + if (variables == null) + throw new CouldNotFindException("variable set for project", project.Name); + + var metadata = new ExportMetadata + { + ExportedAt = DateTime.Now, + OctopusVersion = Repository.Client.RootDocument.Version, + Type = "variables", + ContainerType = "VariableSet" + }; + FileSystemExporter.Export(FilePath, metadata, variables); + } + } +} diff --git a/source/Octo/Importers/IImporterMetadata.cs b/source/Octo/Importers/IImporterMetadata.cs index f5bd8f145..858abb6af 100644 --- a/source/Octo/Importers/IImporterMetadata.cs +++ b/source/Octo/Importers/IImporterMetadata.cs @@ -5,6 +5,5 @@ namespace Octopus.Cli.Importers public interface IImporterMetadata { string Name { get; set; } - string Description { get; set; } } } \ No newline at end of file diff --git a/source/Octo/Importers/ImporterAttribute.cs b/source/Octo/Importers/ImporterAttribute.cs index 4a5d171cd..8f5e2618a 100644 --- a/source/Octo/Importers/ImporterAttribute.cs +++ b/source/Octo/Importers/ImporterAttribute.cs @@ -5,15 +5,11 @@ namespace Octopus.Cli.Importers [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] public class ImporterAttribute : Attribute, IImporterMetadata { - public ImporterAttribute(string name, string entityType) + public ImporterAttribute(string name) { Name = name; - EntityType = entityType; } - public string EntityType { get; set; } - public string Name { get; set; } - public string Description { get; set; } } } \ No newline at end of file diff --git a/source/Octo/Importers/ProjectImporter.cs b/source/Octo/Importers/ProjectImporter.cs index cf65aa128..338f67a9b 100644 --- a/source/Octo/Importers/ProjectImporter.cs +++ b/source/Octo/Importers/ProjectImporter.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Serilog; using Octopus.Cli.Commands; +using Octopus.Cli.Exporters; using Octopus.Cli.Extensions; using Octopus.Cli.Infrastructure; using Octopus.Cli.Repositories; @@ -15,7 +16,7 @@ namespace Octopus.Cli.Importers { - [Importer("project", "ProjectWithDependencies", Description = "Imports a project from an export file")] + [Importer("project")] public class ProjectImporter : BaseImporter { readonly protected ActionTemplateRepository actionTemplateRepository; @@ -49,7 +50,7 @@ public ProjectImporter(IOctopusAsyncRepository repository, IOctopusFileSystem fi protected override async Task Validate(Dictionary paramDictionary) { - var importedObject = FileSystemImporter.Import(FilePath, typeof(ProjectImporter).GetAttributeValue((ImporterAttribute ia) => ia.EntityType)); + var importedObject = FileSystemImporter.Import(FilePath, "ProjectWithDependencies"); var project = importedObject.Project; if (new SemanticVersion(Repository.Client.RootDocument.Version) >= new SemanticVersion(2, 6, 0, 0)) diff --git a/source/Octo/Importers/ReleaseImporter.cs b/source/Octo/Importers/ReleaseImporter.cs index eee564baa..745b506d3 100644 --- a/source/Octo/Importers/ReleaseImporter.cs +++ b/source/Octo/Importers/ReleaseImporter.cs @@ -10,7 +10,7 @@ namespace Octopus.Cli.Importers { - [Importer("release", "List", Description = "Imports a projects releases from an export file")] + [Importer("release")] public class ReleaseImporter : BaseImporter { ValidatedImportSettings validatedImportSettings; @@ -44,7 +44,7 @@ protected override async Task Validate(Dictionary paramDic errorList.Add("Could not find project named '" + projectName + "'"); } - var releases = FileSystemImporter.Import>(FilePath, typeof(ReleaseImporter).GetAttributeValue((ImporterAttribute ia) => ia.EntityType)); + var releases = FileSystemImporter.Import>(FilePath, "List"); if (releases == null) errorList.Add("Unable to deserialize the specified export file"); diff --git a/source/Octo/Importers/VariablesImporter.cs b/source/Octo/Importers/VariablesImporter.cs new file mode 100644 index 000000000..3de9c86eb --- /dev/null +++ b/source/Octo/Importers/VariablesImporter.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Serilog; +using Octopus.Cli.Extensions; +using Octopus.Cli.Util; +using Octopus.Client; +using Octopus.Client.Model; +using Octopus.Cli.Infrastructure; + +namespace Octopus.Cli.Importers +{ + [Importer("variables")] + public class VariablesImporter : BaseImporter + { + ValidatedImportSettings validatedImportSettings; + public bool ReadyToImport => validatedImportSettings != null && !validatedImportSettings.ErrorList.Any(); + + public VariablesImporter(IOctopusAsyncRepository repository, IOctopusFileSystem fileSystem, ILogger log) + : base(repository, fileSystem, log) + { + } + + class ValidatedImportSettings : BaseValidatedImportSettings + { + public ProjectResource Project { get; set; } + public VariableSetResource Variables { get; internal set; } + } + + protected override async Task Validate(Dictionary parameters) + { + var projectName = parameters["Project"]; + if (string.IsNullOrWhiteSpace(projectName)) + { + Log.Error("Please specify the name of the project to export using the parameter: --project=XYZ"); + return false; + } + + Log.Debug("Finding project: {Project:l}", projectName); + var project = await Repository.Projects.FindByName(projectName).ConfigureAwait(false); + if (project == null) + { + Log.Error("a project named", projectName); + return false; + } + + var variables = FileSystemImporter.Import(FilePath, "VariableSet"); + if (variables == null) + { + Log.Error("Unable to deserialize the specified export file"); + return false; + } + + validatedImportSettings = new ValidatedImportSettings + { + Project = project, + Variables = variables + }; + + return true; + } + + protected override async Task Import(Dictionary paramDictionary) + { + var project = validatedImportSettings.Project; + var variables = validatedImportSettings.Variables; + + Log.Debug("Retrieving the current variables for {Project:l}", project.Name); + var current = await Repository.VariableSets.Get(project.VariableSetId); + + variables.Id = current.Id; + variables.OwnerId = current.OwnerId; + variables.Version = current.Version; + + Log.Debug("Updating the variables for {Project:l}", project.Name); + await Repository.VariableSets.Modify(variables); + + Log.Debug("Successfully updated the variables for {Project:l}", project.Name); + } + } +} \ No newline at end of file