Exemple #1
0
        public void Setup()
        {
            mockRepo = Substitute.For <IOctopusAsyncRepository>();

            repoForSpaceScopedResource  = new TestSpaceResourceAsyncRepository(mockRepo, "", async repo => await Task.FromResult(""));
            repoForMixedScopedResource  = new TestMixedResourceAsyncRepository(mockRepo, "");
            repoForSystemScopedResource = new TestSystemResourceAsyncRepository(mockRepo, "", async repo => await Task.FromResult(""));

            mockRepo.LoadRootDocument().Returns(GetRootResource());

            someSpace = new SpaceResource
            {
                Id        = "Spaces-1",
                Name      = "Some Space",
                IsDefault = false
            };

            otherSpace = new SpaceResource()
            {
                Id        = "Spaces-2",
                Name      = "Another space",
                IsDefault = false
            };

            mockRepo.Scope.Returns(RepositoryScope.ForSpace(someSpace));

            RootResource GetRootResource()
            {
                return(new RootResource
                {
                    ApiVersion = "3.0.0",
                    Version = "2099.0.0"
                });
            }
        }
Exemple #2
0
        /// <summary>
        /// Executes the operation against the specified Octopus Deploy server.
        /// </summary>
        /// <param name="repository">The Octopus Deploy server repository.</param>
        /// <exception cref="System.ArgumentException">
        /// </exception>
        public override async Task ExecuteAsync(IOctopusAsyncRepository repository)
        {
            var selectedEnvironments = GetEnvironments(repository).ConfigureAwait(false);
            var machinePolicy        = GetMachinePolicy(repository).ConfigureAwait(false);
            var machineTask          = GetMachine(repository).ConfigureAwait(false);
            var tenants = GetTenants(repository).ConfigureAwait(false);

            await ValidateTenantTags(repository).ConfigureAwait(false);

            var proxy = GetProxy(repository).ConfigureAwait(false);

            var machine = await machineTask;

            ApplyBaseChanges(machine, await machinePolicy, await proxy);
            ApplyDeploymentTargetChanges(machine, await selectedEnvironments, await tenants);

            if (machine.Id != null)
            {
                await repository.Machines.Modify(machine).ConfigureAwait(false);
            }
            else
            {
                await repository.Machines.Create(machine).ConfigureAwait(false);
            }
        }
Exemple #3
0
 protected BasicRepository(IOctopusAsyncRepository repository, string collectionLinkName, Func <IOctopusAsyncRepository, Task <string> > getCollectionLinkName = null)
 {
     Client                     = repository.Client;
     Repository                 = repository;
     CollectionLinkName         = collectionLinkName;
     this.getCollectionLinkName = getCollectionLinkName;
 }
Exemple #4
0
        async Task <List <TenantResource> > GetTenants(IOctopusAsyncRepository repository)
        {
            if (Tenants == null || !Tenants.Any())
            {
                return(new List <TenantResource>());
            }

            var tenantsByName = new List <TenantResource>();

            foreach (var tenantName in Tenants)
            {
                var tenant = await repository.Tenants.FindByName(tenantName).ConfigureAwait(false);

                if (tenant != null)
                {
                    tenantsByName.Add(tenant);
                }
            }

            var missing = Tenants.Except(tenantsByName.Select(e => e.Name), StringComparer.OrdinalIgnoreCase).ToArray();

            var tenantsById = await repository.Tenants.Get(missing).ConfigureAwait(false);

            missing = missing.Except(tenantsById.Select(e => e.Id), StringComparer.OrdinalIgnoreCase).ToArray();

            if (missing.Any())
            {
                throw new ArgumentException(CouldNotFindMessage("tenant", missing));
            }

            return(tenantsById.Concat(tenantsByName).ToList());
        }
        public static async Task <Project> ToModel(this ProjectResource resource, IOctopusAsyncRepository repository)
        {
            var deploymentProcessResource = await repository.DeploymentProcesses.Get(resource.DeploymentProcessId);

            var variableSetResource = await repository.VariableSets.Get(resource.VariableSetId);

            var libraryVariableSetRefs = await Task.WhenAll(resource.IncludedLibraryVariableSetIds.Select(async id => new ElementReference((await repository.LibraryVariableSets.Get(id)).Name)));

            var lifecycleResource = await repository.Lifecycles.Get(resource.LifecycleId);

            var projectGroupResource = await repository.ProjectGroups.Get(resource.ProjectGroupId);

            var triggers = await repository.Projects.GetTriggers(resource);

            return(new Project(
                       new ElementIdentifier(resource.Name),
                       resource.Description,
                       resource.IsDisabled,
                       resource.AutoCreateRelease,
                       resource.DefaultToSkipIfAlreadyInstalled,
                       await deploymentProcessResource.ToModel(repository),
                       await variableSetResource.ToModel(deploymentProcessResource, repository),
                       libraryVariableSetRefs,
                       new ElementReference(lifecycleResource.Name),
                       new ElementReference(projectGroupResource.Name),
                       resource.VersioningStrategy?.ToModel(),
                       await Task.WhenAll(triggers.Items.Select(t => t.ToModel(repository))),
                       (OctopusProjectBuilder.Model.TenantedDeploymentMode)resource.TenantedDeploymentMode));
        }
 public static async Task <Tenant> ToModel(this TenantResource resource, IOctopusAsyncRepository repository)
 {
     return(new Tenant(
                new ElementIdentifier(resource.Name),
                resource.TenantTags.Select(x => new ElementReference(x)).ToArray(),
                await resource.ProjectEnvironments.ToModel(repository)));
 }
 public async Task <ReleasePlan> Build(IOctopusAsyncRepository repository, ProjectResource project,
                                       ChannelResource channel, string versionPreReleaseTag, string gitReference)
 {
     return(string.IsNullOrWhiteSpace(gitReference)
         ? await BuildReleaseFromDatabase(repository, project, channel, versionPreReleaseTag)
         : await BuildReleaseFromVersionControl(repository, project, channel, versionPreReleaseTag, gitReference));
 }
Exemple #8
0
        public async Task Render(IOctopusAsyncRepository repository, ICommandOutputProvider commandOutputProvider, TaskResource resource)
        {
            var details = await repository.Tasks.GetDetails(resource).ConfigureAwait(false);

            if (details.ActivityLogs != null)
            {
                foreach (var item in details.ActivityLogs.SelectMany(a => a.Children))
                {
                    if (commandOutputProvider.ServiceMessagesEnabled())
                    {
                        if (commandOutputProvider.IsVSTS())
                        {
                            RenderToVSTS(item, commandOutputProvider, string.Empty);
                        }
                        else
                        {
                            RenderToTeamCity(item, commandOutputProvider);
                        }
                    }
                    else
                    {
                        RenderToConsole(item, commandOutputProvider, string.Empty);
                    }
                }
            }
        }
Exemple #9
0
        public async Task Render(IOctopusAsyncRepository repository, ILogger log, TaskResource resource)
        {
            var details = await repository.Tasks.GetDetails(resource).ConfigureAwait(false);

            if (details.ActivityLogs != null)
            {
                foreach (var item in details.ActivityLogs)
                {
                    if (log.ServiceMessagesEnabled())
                    {
                        if (log.IsVSTS())
                        {
                            RenderToVSTS(item, log, "");
                        }
                        else
                        {
                            RenderToTeamCity(item, log);
                        }
                    }
                    else
                    {
                        RenderToConsole(item, log, "");
                    }
                }
            }
        }
 public HealthStatusProvider(IOctopusAsyncRepository repository, HashSet <string> statuses, HashSet <string> healthStatuses, ICommandOutputProvider commandOutputProvider)
 {
     this.statuses                    = statuses;
     this.healthStatuses              = healthStatuses;
     this.commandOutputProvider       = commandOutputProvider;
     IsHealthStatusPendingDeprication = (new SemanticVersion(repository.Client.RootDocument.Version).Version >= new SemanticVersion("3.4.0").Version);
     ValidateOptions();
 }
Exemple #11
0
        /// <summary>
        /// Run the fixture
        /// </summary>
        public static void Run()
        {
            _repository = OctopusRepository.GetRepository().Result;

            Log.Logger.Information("**Running Library Fixture**");

            CreateLibraryStuff();
        }
 public HealthStatusProvider(IOctopusAsyncRepository repository, HashSet <MachineModelStatus> statuses, HashSet <MachineModelHealthStatus> healthStatuses, ICommandOutputProvider commandOutputProvider, RootResource rootDocument)
 {
     this.statuses                    = statuses;
     this.healthStatuses              = healthStatuses;
     this.commandOutputProvider       = commandOutputProvider;
     IsHealthStatusPendingDeprication = (new SemanticVersion(rootDocument.Version).Version >= new SemanticVersion("3.4.0").Version);
     ValidateOptions();
 }
Exemple #13
0
 public HealthStatusProvider(IOctopusAsyncRepository repository, ILogger log, HashSet <string> statuses, HashSet <string> healthStatuses)
 {
     this.log            = log;
     this.statuses       = statuses;
     this.healthStatuses = healthStatuses;
     IsHealthStatusPendingDeprication = (new SemanticVersion(repository.Client.RootDocument.Version).Version >= new SemanticVersion("3.4.0").Version);
     ValidateOptions();
 }
 public HealthStatusProvider(IOctopusAsyncRepository repository, ILogger log, HashSet<string> statuses, HashSet<string> healthStatuses)
 {
     this.log = log;
     this.statuses = statuses;
     this.healthStatuses = healthStatuses;
     IsHealthStatusPendingDeprication = (new SemanticVersion(repository.Client.RootDocument.Version).Version >= new SemanticVersion("3.4.0").Version);
     ValidateOptions();
 }
Exemple #15
0
        private async Task <ProjectResource> GetProjectResource(string projectName, IOctopusAsyncRepository repository)
        {
            var project = await repository.Projects.FindByName(projectName);

            if (project == null)
            {
                throw new Exception($"Project with name of '{projectName}' not found");
            }
            return(project);
        }
Exemple #16
0
 public ExecutionResourceWaiter(
     ICommandOutputProvider commandOutputProvider,
     IOctopusAsyncRepository repository,
     string serverBaseUrl
     )
 {
     this.commandOutputProvider = commandOutputProvider;
     this.repository            = repository;
     this.serverBaseUrl         = serverBaseUrl;
 }
Exemple #17
0
        static async Task <Dictionary <string, FeedResource> > LoadFeedsForSteps(IOctopusAsyncRepository repository, ProjectResource project, IEnumerable <ReleasePlanItem> steps)
        {
            // PackageFeedId can be an id or a name
            var allRelevantFeedIdOrName = steps.Select(step => step.PackageFeedId).ToArray();
            var allRelevantFeeds        = project.IsVersionControlled
                ? (await repository.Feeds.FindByNames(allRelevantFeedIdOrName).ConfigureAwait(false)).ToDictionary(feed => feed.Name)
                : (await repository.Feeds.Get(allRelevantFeedIdOrName).ConfigureAwait(false)).ToDictionary(feed => feed.Id);

            return(allRelevantFeeds);
        }
Exemple #18
0
 public static async Task <Team> ToModel(this TeamResource resource, IOctopusAsyncRepository repository)
 {
     return(new Team(
                new ElementIdentifier(resource.Name),
                await Task.WhenAll(resource.MemberUserIds.Select(async mui => new ElementReference((await repository.Users.Get(mui)).Username))),
                resource.ExternalSecurityGroups.Select(esg => esg.Id),
                await Task.WhenAll(resource.UserRoleIds.ToModel(repository.UserRoles)),
                await Task.WhenAll(resource.ProjectIds.ToModel(repository.Projects)),
                await Task.WhenAll(resource.EnvironmentIds.ToModel(repository.Environments))));
 }
        /// <summary>
        /// Run the fixture
        /// </summary>
        public static void Run()
        {
            _repository = OctopusRepository.GetRepository().Result;

            Log.Logger.Information("**Running Configuration Fixture**");

            SetFeatures();
            CreateTeams();
            CreateUserRoles();
            CreateUsers();
        }
        public static async Task <bool> SupportsChannels(this IOctopusAsyncRepository repository)
        {
            var hasChannelLink = await repository.HasLink("Channels").ConfigureAwait(false) == true;

            if (!hasChannelLink)
            {
                // When default space is off and SpaceId is not provided, we check if it is in post space world, as channels are always available in spaces
                return(await repository.HasLink("SpaceHome").ConfigureAwait(false) == true);
            }

            return(true);
        }
Exemple #21
0
        async Task <List <WorkerPoolResource> > GetWorkerPools(IOctopusAsyncRepository repository)
        {
            var selectedPools = await repository.WorkerPools.FindByNames(WorkerPoolNames).ConfigureAwait(false);

            var missing = WorkerPoolNames.Except(selectedPools.Select(p => p.Name), StringComparer.OrdinalIgnoreCase).ToList();

            if (missing.Any())
            {
                throw new ArgumentException(CouldNotFindMessage("worker pool", missing.ToArray()));
            }

            return(selectedPools);
        }
        async Task <List <EnvironmentResource> > GetEnvironments(IOctopusAsyncRepository repository)
        {
            var selectedEnvironments = await repository.Environments.FindByNames(EnvironmentNames).ConfigureAwait(false);

            var missing = EnvironmentNames.Except(selectedEnvironments.Select(e => e.Name), StringComparer.OrdinalIgnoreCase).ToList();

            if (missing.Any())
            {
                throw new ArgumentException(CouldNotFindMessage("environment", missing.ToArray()));
            }

            return(selectedEnvironments);
        }
        public IExporter Find(string name, IOctopusAsyncRepository repository, IOctopusFileSystem fileSystem, ILogger log)
        {
            var iExporterType = typeof (IExporter).GetTypeInfo();
            name = name.Trim().ToLowerInvariant();
            var found = (from t in typeof (ExporterLocator).GetTypeInfo().Assembly.GetTypes()
                where iExporterType.IsAssignableFrom(t)
                let attribute = (IExporterMetadata) t.GetTypeInfo().GetCustomAttributes(typeof (ExporterAttribute), true).FirstOrDefault()
                where attribute != null
                where attribute.Name == name
                select t).FirstOrDefault();

            return found == null ? null : (IExporter) lifetimeScope.Resolve(found, new TypedParameter(typeof (IOctopusAsyncRepository), repository), new TypedParameter(typeof (IOctopusFileSystem), fileSystem), new TypedParameter(typeof (ILogger), log));
        }
Exemple #24
0
        public async Task Execute(string[] commandLineArguments)
        {
            var remainingArguments = optionGroups.Parse(commandLineArguments);

            if (remainingArguments.Count > 0)
            {
                throw new CommandException("Unrecognized command arguments: " + string.Join(", ", remainingArguments));
            }

            if (string.IsNullOrWhiteSpace(serverBaseUrl))
            {
                serverBaseUrl = "http://localhost:8065";
                log.Information($"No Octopus Server URL was provided. Using default development value: {serverBaseUrl}");
            }

            if (string.IsNullOrWhiteSpace(apiKey) &&
                string.IsNullOrWhiteSpace(username) &&
                string.IsNullOrWhiteSpace(password))
            {
                username = "******";
                password = "******";
                log.Information("No credentials were provided. Using default development credentials.");
            }

            if (string.IsNullOrWhiteSpace(serverBaseUrl))
            {
                throw new CommandException("Please specify the Octopus Server URL using --server=http://your-server/");
            }

            if (string.IsNullOrWhiteSpace(apiKey) && (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password)))
            {
                throw new CommandException("Please specify either your API key using --apiKey=ABCDEF123456789, or your Octopus credentials using --user=MyName --pass=Secret.");
            }

            var credentials = ParseCredentials(username, password);

            var endpoint = new OctopusServerEndpoint(serverBaseUrl, apiKey, credentials);

            using (var client = await octopusClientFactory.CreateAsyncClient(endpoint))
            {
                Repository = client.Repository;
                client.SendingOctopusRequest +=
                    request => log.Debug("{Method} {Uri}", request.Method, request.Uri);

                ConfigureServerCertificateValidation();

                await InitializeConnection();

                await Execute();
            }
        }
Exemple #25
0
        public IExporter Find(string name, IOctopusAsyncRepository repository, IOctopusFileSystem fileSystem, ILogger log)
        {
            var iExporterType = typeof(IExporter).GetTypeInfo();

            name = name.Trim().ToLowerInvariant();
            var found = (from t in typeof(ExporterLocator).GetTypeInfo().Assembly.GetTypes()
                         where iExporterType.IsAssignableFrom(t)
                         let attribute = (IExporterMetadata)t.GetTypeInfo().GetCustomAttributes(typeof(ExporterAttribute), true).FirstOrDefault()
                                         where attribute != null
                                         where attribute.Name == name
                                         select t).FirstOrDefault();

            return(found == null ? null : (IExporter)lifetimeScope.Resolve(found, new TypedParameter(typeof(IOctopusAsyncRepository), repository), new TypedParameter(typeof(IOctopusFileSystem), fileSystem), new TypedParameter(typeof(ILogger), log)));
        }
        public static async Task ValidateRoles(this IOctopusAsyncRepository octopusRepository, IEnumerable <string> roles)
        {
            var serverRolesList = await octopusRepository.MachineRoles.GetAllRoleNames().ConfigureAwait(false);

            var serverRoles = new HashSet <string>(serverRolesList);

            foreach (var role in roles)
            {
                if (!serverRoles.Contains(role))
                {
                    throw new ArgumentException($"Unable to find a machine role with the name '{role}'");
                }
            }
        }
Exemple #27
0
        protected async Task <ProxyResource> GetProxy(IOctopusAsyncRepository repository)
        {
            var proxy = default(ProxyResource);

            if (!string.IsNullOrEmpty(ProxyName))
            {
                proxy = await repository.Proxies.FindByName(ProxyName).ConfigureAwait(false);

                if (proxy == null)
                {
                    throw new ArgumentException(CouldNotFindMessage("proxy name", ProxyName));
                }
            }
            return(proxy);
        }
        async Task <MachinePolicyResource> GetMachinePolicy(IOctopusAsyncRepository repository)
        {
            var machinePolicy = default(MachinePolicyResource);

            if (!string.IsNullOrEmpty(MachinePolicy))
            {
                machinePolicy = await repository.MachinePolicies.FindByName(MachinePolicy).ConfigureAwait(false);

                if (machinePolicy == null)
                {
                    throw new ArgumentException(CouldNotFindMessage("machine policy", MachinePolicy));
                }
            }
            return(machinePolicy);
        }
        async Task ValidateTenantTags(IOctopusAsyncRepository repository)
        {
            if (TenantTags == null || !TenantTags.Any())
            {
                return;
            }

            var tagSets = await repository.TagSets.FindAll().ConfigureAwait(false);

            var missingTags = TenantTags.Where(tt => !tagSets.Any(ts => ts.Tags.Any(t => t.CanonicalTagName.Equals(tt, StringComparison.OrdinalIgnoreCase)))).ToList();

            if (missingTags.Any())
            {
                throw new ArgumentException(CouldNotFindMessage("tag", missingTags.ToArray()));
            }
        }
        /// <summary>
        /// Run the fixture
        /// </summary>
        public static void Run()
        {
            _repository = OctopusRepository.GetRepository().Result;

            Log.Logger.Information("**Running Infrastructure Fixture**");

            var pgs = CreateProjectGroups();

            CreateLifecycles();
            CreateProjects(pgs);
            CreateLifecycles();
            CreateTagSets();
            CreateTenants();

            Log.Logger.Information("**Finished running Infrastructure Fixture**");
        }
        async Task <MachineResource> GetMachine(IOctopusAsyncRepository repository)
        {
            var existing = default(MachineResource);

            try
            {
                existing = await repository.Machines.FindByName(MachineName).ConfigureAwait(false);

                if (!AllowOverwrite && existing?.Id != null)
                {
                    throw new ArgumentException($"A machine named '{MachineName}' already exists in the environment. Use the 'force' parameter if you intended to update the existing machine.");
                }
            }
            catch (OctopusDeserializationException) // eat it, probably caused by resource incompatability between versions
            {
            }
            return(existing ?? new MachineResource());
        }
Exemple #32
0
        async Task <ReleasePlan> BuildReleaseFromVersionControl(IOctopusAsyncRepository repository,
                                                                ProjectResource project,
                                                                ChannelResource channel,
                                                                string versionPreReleaseTag,
                                                                string gitReference)
        {
            if (repository == null)
            {
                throw new ArgumentNullException(nameof(repository));
            }
            if (project == null)
            {
                throw new ArgumentNullException(nameof(project));
            }
            if (!project.IsVersionControlled)
            {
                throw new CommandException(GitReferenceSuppliedForDatabaseProjectErrorMessage(gitReference));
            }
            commandOutputProvider.Debug($"Finding deployment process at git reference {gitReference}...");
            var deploymentProcess = await repository.DeploymentProcesses.Beta().Get(project, gitReference);

            if (deploymentProcess == null)
            {
                throw new CouldNotFindException(
                          $"a deployment process for project {project.Name} and git reference {gitReference}");
            }

            commandOutputProvider.Debug($"Finding release template at git reference {gitReference}...");
            var releaseTemplate = await repository.DeploymentProcesses.GetTemplate(deploymentProcess, channel).ConfigureAwait(false);

            if (releaseTemplate == null)
            {
                throw new CouldNotFindException(
                          $"a release template for project {project.Name}, channel {channel.Name} and git reference {gitReference}");
            }

            return(await Build(repository,
                               project,
                               channel,
                               versionPreReleaseTag,
                               releaseTemplate,
                               deploymentProcess));
        }
        public async Task Render(IOctopusAsyncRepository repository, ILogger log, TaskResource resource)
        {
            var details = await repository.Tasks.GetDetails(resource).ConfigureAwait(false);

            if (details.ActivityLogs != null)
            {
                foreach (var item in details.ActivityLogs)
                {
                    if (log.ServiceMessagesEnabled())
                    {
                        if (log.IsVSTS())
                            RenderToVSTS(item, log, "");
                        else
                            RenderToTeamCity(item, log);
                    }
                    else
                    {
                        RenderToConsole(item, log, "");                        
                    }
                }
            }
        }
        public async Task<ChannelVersionRuleTestResult> Test(IOctopusAsyncRepository repository, ChannelVersionRuleResource rule, string packageVersion)
        {
            if (rule == null)
            {
                // Anything goes if there is no rule defined for this step
                return ChannelVersionRuleTestResult.Null();
            }

            var link = repository.Client.RootDocument.Link("VersionRuleTest");

            var resource = new
            {
                version = packageVersion,
                versionRange = rule.VersionRange,
                preReleaseTag = rule.Tag
            };

            var response = repository.Client.RootDocument.UsePostForChannelVersionRuleTest()
                ? repository.Client.Post<object, ChannelVersionRuleTestResult>(link, resource)
                : repository.Client.Get<ChannelVersionRuleTestResult>(link, resource);

            return await response.ConfigureAwait(false);
        }
 public ReleaseImporter(IOctopusAsyncRepository repository, IOctopusFileSystem fileSystem, ILogger log)
     : base(repository, fileSystem, log)
 {
 }
 public ProjectExporter(IOctopusAsyncRepository repository, IOctopusFileSystem fileSystem, ILogger log)
     : base(repository, fileSystem, log)
 {
     actionTemplateRepository = new ActionTemplateRepository(repository.Client);
 }
 public OctopusRepositoryCommonQueries(IOctopusAsyncRepository repository, ILogger log)
 {
     this.repository = repository;
     this.log = log;
 }
        public async Task<ReleasePlan> Build(IOctopusAsyncRepository repository, ProjectResource project, ChannelResource channel, string versionPreReleaseTag)
        {
            if (repository == null) throw new ArgumentNullException(nameof(repository));
            if (project == null) throw new ArgumentNullException(nameof(project));

            log.Debug("Finding deployment process...");
            var deploymentProcess = await repository.DeploymentProcesses.Get(project.DeploymentProcessId).ConfigureAwait(false);

            log.Debug("Finding release template...");
            var releaseTemplate = await repository.DeploymentProcesses.GetTemplate(deploymentProcess, channel).ConfigureAwait(false);

            var plan = new ReleasePlan(project, channel, releaseTemplate, versionResolver);

            if (plan.UnresolvedSteps.Any())
            {
                log.Debug("The package version for some steps was not specified. Going to try and resolve those automatically...");
                foreach (var unresolved in plan.UnresolvedSteps)
                {
                    if (!unresolved.IsResolveable)
                    {
                        log.Error("The version number for step '{Step:l}' cannot be automatically resolved because the feed or package ID is dynamic.", unresolved.StepName);
                        continue;
                    }

                    if (!string.IsNullOrEmpty(versionPreReleaseTag))
                        log.Debug("Finding latest package with pre-release '{Tag:l}' for step: {StepName:l}", versionPreReleaseTag, unresolved.StepName);
                    else
                        log.Debug("Finding latest package for step: {StepName:l}", unresolved.StepName);

                    var feed = await repository.Feeds.Get(unresolved.PackageFeedId).ConfigureAwait(false);
                    if (feed == null)
                        throw new CommandException(string.Format("Could not find a feed with ID {0}, which is used by step: " + unresolved.StepName, unresolved.PackageFeedId));

                    var filters = BuildChannelVersionFilters(unresolved.StepName, channel);
                    filters["packageId"] = unresolved.PackageId;
                    if (!string.IsNullOrWhiteSpace(versionPreReleaseTag))
                        filters["preReleaseTag"] = versionPreReleaseTag;

                    var packages = await repository.Client.Get<List<PackageResource>>(feed.Link("SearchTemplate"), filters).ConfigureAwait(false);
                    var latestPackage = packages.FirstOrDefault();

                    if (latestPackage == null)
                    {
                        log.Error("Could not find any packages with ID '{PackageId:l}' in the feed '{FeedUri:l}'", unresolved.PackageId, feed.FeedUri);
                    }
                    else
                    {
                        log.Debug("Selected '{PackageId:l}' version '{Version:l}' for '{StepName:l}'", latestPackage.PackageId, latestPackage.Version, unresolved.StepName);
                        unresolved.SetVersionFromLatest(latestPackage.Version);
                    }
                }
            }

            // Test each step in this plan satisfies the channel version rules
            if (channel != null)
            {
                foreach (var step in plan.Steps)
                {
                    // Note the rule can be null, meaning: anything goes
                    var rule = channel.Rules.SingleOrDefault(r => r.Actions.Any(s => s.Equals(step.StepName, StringComparison.OrdinalIgnoreCase)));
                    var result = await versionRuleTester.Test(repository, rule, step.Version).ConfigureAwait(false);
                    step.SetChannelVersionRuleTestResult(result);
                }
            }

            return plan;
        }
 protected BaseExporter(IOctopusAsyncRepository repository, IOctopusFileSystem fileSystem, ILogger log)
 {
     this.Log = log;
     this.Repository = repository;
     FileSystemExporter = new FileSystemExporter(fileSystem, log);
 }