private async Task <PartitionAddressInformation> GetAddressesForRangeIdAsync( DocumentServiceRequest request, string collectionRid, string partitionKeyRangeId, bool forceRefresh) { FeedResource <Address> response = await this.GetServerAddressesViaGatewayAsync(request, collectionRid, new[] { partitionKeyRangeId }, forceRefresh); IEnumerable <Tuple <PartitionKeyRangeIdentity, PartitionAddressInformation> > addressInfos = response.Where(addressInfo => ProtocolFromString(addressInfo.Protocol) == this.protocol) .GroupBy(address => address.PartitionKeyRangeId, StringComparer.Ordinal) .Select(group => this.ToPartitionAddressAndRange(collectionRid, @group.ToList())); Tuple <PartitionKeyRangeIdentity, PartitionAddressInformation> result = addressInfos.SingleOrDefault( addressInfo => StringComparer.Ordinal.Equals(addressInfo.Item1.PartitionKeyRangeId, partitionKeyRangeId)); if (result == null) { string errorMessage = string.Format( CultureInfo.InvariantCulture, RMResources.PartitionKeyRangeNotFound, partitionKeyRangeId, collectionRid); throw new PartitionKeyRangeGoneException(errorMessage) { ResourceAddress = collectionRid }; } return(result.Item2); }
public static FeedResource CustomExpressionFeedWithId(string id) { var feed = new FeedResource() { Id = id, Name = FeedCustomExpressionHelper.CustomExpressionFeedName }; return(feed); }
private async Task <Tuple <PartitionKeyRangeIdentity, PartitionAddressInformation> > ResolveMasterAsync(DocumentServiceRequest request, bool forceRefresh) { Tuple <PartitionKeyRangeIdentity, PartitionAddressInformation> masterAddressAndRange = this.masterPartitionAddressCache; int targetReplicaSetSize = this.serviceConfigReader.SystemReplicationPolicy.MaxReplicaSetSize; forceRefresh = forceRefresh || (masterAddressAndRange != null && masterAddressAndRange.Item2.AllAddresses.Count() < targetReplicaSetSize && DateTime.UtcNow.Subtract(this.suboptimalMasterPartitionTimestamp) > TimeSpan.FromSeconds(this.suboptimalPartitionForceRefreshIntervalInSeconds)); if (forceRefresh || request.ForceCollectionRoutingMapRefresh || this.masterPartitionAddressCache == null) { string entryUrl = PathsHelper.GeneratePath( ResourceType.Database, string.Empty, true); try { using (DocumentServiceResponse response = await this.GetMasterAddressesViaGatewayAsync( request, ResourceType.Database, null, entryUrl, forceRefresh, false)) { FeedResource <Address> masterAddresses = response.GetResource <FeedResource <Address> >(); bool inNetworkRequest = this.IsInNetworkRequest(response); masterAddressAndRange = this.ToPartitionAddressAndRange(string.Empty, masterAddresses.ToList(), inNetworkRequest); this.masterPartitionAddressCache = masterAddressAndRange; this.suboptimalMasterPartitionTimestamp = DateTime.MaxValue; } } catch (Exception) { this.suboptimalMasterPartitionTimestamp = DateTime.MaxValue; throw; } } if (masterAddressAndRange.Item2.AllAddresses.Count() < targetReplicaSetSize && this.suboptimalMasterPartitionTimestamp.Equals(DateTime.MaxValue)) { this.suboptimalMasterPartitionTimestamp = DateTime.UtcNow; } return(masterAddressAndRange); }
public static async Task <ICollection <T> > ListAllAsync <T>(this HttpClient client, Uri collectionUri, INameValueCollection headers = null) where T : CosmosResource, new() { Collection <T> responseCollection = new Collection <T>(); string responseContinuation = null; if (headers == null) { headers = new StringKeyValueCollection(); } do { if (responseContinuation != null) { headers[HttpConstants.HttpHeaders.Continuation] = responseContinuation; } HttpResponseMessage responseMessage; foreach (var header in headers.AllKeys()) { client.DefaultRequestHeaders.Add(header, headers[header]); } responseMessage = await client.GetAsync(collectionUri, HttpCompletionOption.ResponseHeadersRead); FeedResource <T> feedResource = await responseMessage.ToResourceAsync <FeedResource <T> >(); foreach (T resource in feedResource) { responseCollection.Add(resource); } IEnumerable <string> continuationToken = null; if (responseMessage.Headers.TryGetValues(HttpConstants.HttpHeaders.Continuation, out continuationToken)) { responseContinuation = continuationToken.SingleOrDefault(); } else { responseContinuation = null; } } while (!string.IsNullOrEmpty(responseContinuation)); return(responseCollection); }
static void Main(string[] args) { var endpoint = new OctopusServerEndpoint("http://localhost/"); var repository = new OctopusRepository(endpoint); repository.Users.SignIn(new LoginCommand { Username = "******", Password = "******" }); var integrationEnvironment = CreateEnvironment(repository, "Integration"); var uatEnvironment = CreateEnvironment(repository, "UAT"); var productionEnvironment = CreateEnvironment(repository, "Production"); var environments = new[] { integrationEnvironment, uatEnvironment, productionEnvironment }; var integrationMachine = CreateMachine(repository, integrationEnvironment, "Integration"); var uatMachine = CreateMachine(repository, uatEnvironment, "UAT"); var productionMachine = CreateMachine(repository, productionEnvironment, "Production"); var projectGroup = CreateProjectGroup(repository); var lifecycle = repository.Lifecycles.FindOne(l => l.Name == "Default Lifecycle"); var project = CreateProject(repository, projectGroup, lifecycle, "SimpleTalk"); FeedResource feed = null; try { feed = repository.Feeds.Create(new FeedResource { Name = "TeamCity", FeedUri = "http://localhost/" }); } catch (Exception) { feed = repository.Feeds.FindByName("TeamCity"); } CreateDeploymentProcess(repository, project, feed); CreateDashboard(repository, environments, project); CreateActionTemplate(repository); }
protected async Task <CheckedReferences <FeedResource> > CheckNuGetFeedsExist(List <ReferenceDataItem> nugetFeeds) { Log.Debug("Checking that all NuGet Feeds exist"); var dependencies = new CheckedReferences <FeedResource>(); foreach (var nugetFeed in nugetFeeds) { FeedResource feed = null; if (FeedCustomExpressionHelper.IsRealFeedId(nugetFeed.Id)) { feed = await Repository.Feeds.FindByName(nugetFeed.Name).ConfigureAwait(false); } else { feed = FeedCustomExpressionHelper.CustomExpressionFeedWithId(nugetFeed.Id); } dependencies.Register(nugetFeed.Name, nugetFeed.Id, feed); } return(dependencies); }
private async Task <CollectionRoutingMap> GetRoutingMapForCollectionAsync( string collectionRid, CollectionRoutingMap previousRoutingMap, ITrace trace, IClientSideRequestStatistics clientSideRequestStatistics, CancellationToken cancellationToken) { List <PartitionKeyRange> ranges = new List <PartitionKeyRange>(); string changeFeedNextIfNoneMatch = previousRoutingMap == null ? null : previousRoutingMap.ChangeFeedNextIfNoneMatch; HttpStatusCode lastStatusCode = HttpStatusCode.OK; do { INameValueCollection headers = new StoreRequestNameValueCollection(); headers.Set(HttpConstants.HttpHeaders.PageSize, PageSizeString); headers.Set(HttpConstants.HttpHeaders.A_IM, HttpConstants.A_IMHeaderValues.IncrementalFeed); if (changeFeedNextIfNoneMatch != null) { headers.Set(HttpConstants.HttpHeaders.IfNoneMatch, changeFeedNextIfNoneMatch); } RetryOptions retryOptions = new RetryOptions(); using (DocumentServiceResponse response = await BackoffRetryUtility <DocumentServiceResponse> .ExecuteAsync( () => this.ExecutePartitionKeyRangeReadChangeFeedAsync(collectionRid, headers, trace, clientSideRequestStatistics), new ResourceThrottleRetryPolicy(retryOptions.MaxRetryAttemptsOnThrottledRequests, retryOptions.MaxRetryWaitTimeInSeconds), cancellationToken)) { lastStatusCode = response.StatusCode; changeFeedNextIfNoneMatch = response.Headers[HttpConstants.HttpHeaders.ETag]; FeedResource <PartitionKeyRange> feedResource = response.GetResource <FeedResource <PartitionKeyRange> >(); if (feedResource != null) { ranges.AddRange(feedResource); } } }while (lastStatusCode != HttpStatusCode.NotModified); IEnumerable <Tuple <PartitionKeyRange, ServiceIdentity> > tuples = ranges.Select(range => Tuple.Create(range, (ServiceIdentity)null)); CollectionRoutingMap routingMap; if (previousRoutingMap == null) { // Splits could have happened during change feed query and we might have a mix of gone and new ranges. HashSet <string> goneRanges = new HashSet <string>(ranges.SelectMany(range => range.Parents ?? Enumerable.Empty <string>())); routingMap = CollectionRoutingMap.TryCreateCompleteRoutingMap( tuples.Where(tuple => !goneRanges.Contains(tuple.Item1.Id)), string.Empty, changeFeedNextIfNoneMatch); } else { routingMap = previousRoutingMap.TryCombine(tuples, changeFeedNextIfNoneMatch); } if (routingMap == null) { // Range information either doesn't exist or is not complete. throw new NotFoundException($"{DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture)}: GetRoutingMapForCollectionAsync(collectionRid: {collectionRid}), Range information either doesn't exist or is not complete."); } return(routingMap); }
public void Setup() { // setup data objects channelVersionRules = new List <ChannelVersionRuleResource>(); projectResource = new ProjectResource { DeploymentProcessId = TestHelpers.GetId("deploymentprocess"), Id = TestHelpers.GetId("project") }; deploymentProcessResource = new DeploymentProcessResource { ProjectId = projectResource.Id, Id = projectResource.DeploymentProcessId }; releaseTemplateResource = new ReleaseTemplateResource { DeploymentProcessId = projectResource.DeploymentProcessId, Packages = new List <ReleaseTemplatePackage>(), Id = TestHelpers.GetId("releaseTemplate") }; channelResource = new ChannelResource { IsDefault = true, Id = TestHelpers.GetId("channel"), ProjectId = projectResource.Id, Rules = channelVersionRules, Name = TestHelpers.GetId("channelname") }; feedResource = new FeedResource { Links = new LinkCollection { { "SearchTemplate", TestHelpers.GetId("searchUri") } } }; // setup mocks logger = Substitute.For <ILogger>(); versionResolver = Substitute.For <IPackageVersionResolver>(); versionRuleTester = Substitute.For <IChannelVersionRuleTester>(); deploymentProcessRepository = Substitute.For <IDeploymentProcessRepository>(); deploymentProcessRepository.Get(projectResource.DeploymentProcessId) .Returns(Task.FromResult(deploymentProcessResource)); deploymentProcessRepository .GetTemplate(Arg.Is <DeploymentProcessResource>(deploymentProcessResource), Arg.Is <ChannelResource>(channelResource)).Returns(Task.FromResult(releaseTemplateResource)); versionRuleTester .Test(Arg.Any <IOctopusAsyncRepository>(), Arg.Any <ChannelVersionRuleResource>(), Arg.Any <string>()) .Returns(Task.FromResult(channelVersionRuleTestResult)); releaseRepository = Substitute.For <IReleaseRepository>(); feedRepository = Substitute.For <IFeedRepository>(); feedRepository.Get(Arg.Any <string>()).Returns(feedResource); repository = Substitute.For <IOctopusAsyncRepository>(); repository.DeploymentProcesses.Returns(deploymentProcessRepository); repository.Releases.Returns(releaseRepository); repository.Feeds.Returns(feedRepository); repository.Client .Get <List <PackageResource> >(Arg.Any <string>(), Arg.Any <IDictionary <string, object> >()).Returns(packages); builder = new ReleasePlanBuilder(logger, versionResolver, versionRuleTester); }
protected override async Task Export(Dictionary <string, string> parameters) { if (string.IsNullOrWhiteSpace(parameters["Name"])) { throw new CommandException("Please specify the name of the project to export using the parameter: --name=XYZ"); } var projectName = parameters["Name"]; 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 project group for project"); var projectGroup = await Repository.ProjectGroups.Get(project.ProjectGroupId).ConfigureAwait(false); if (projectGroup == null) { throw new CouldNotFindException("project group for project", project.Name); } 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 channelLifecycles = new List <ReferenceDataItem>(); var channels = new ChannelResource[0]; if (Repository.SupportsChannels()) { Log.Debug("Finding channels for project"); var firstChannelPage = await Repository.Projects.GetChannels(project).ConfigureAwait(false); channels = (await firstChannelPage.GetAllPages(Repository).ConfigureAwait(false)).ToArray(); foreach (var channel in channels.ToArray()) { if (channel.LifecycleId != null) { var channelLifecycle = await Repository.Lifecycles.Get(channel.LifecycleId).ConfigureAwait(false); if (channelLifecycle == null) { throw new CouldNotFindException("Lifecycle for channel", channel.Name); } if (channelLifecycles.All(cl => cl.Id != channelLifecycle.Id)) { channelLifecycles.Add(new ReferenceDataItem(channelLifecycle.Id, channelLifecycle.Name)); } } } } Log.Debug("Finding deployment process for project"); var deploymentProcess = await Repository.DeploymentProcesses.Get(project.DeploymentProcessId).ConfigureAwait(false); if (deploymentProcess == null) { throw new CouldNotFindException("deployment process for project", project.Name); } Log.Debug("Finding NuGet feed for deployment process..."); var nugetFeeds = new List <ReferenceDataItem>(); foreach (var step in deploymentProcess.Steps) { foreach (var action in step.Actions) { PropertyValueResource nugetFeedId; if (action.Properties.TryGetValue("Octopus.Action.Package.NuGetFeedId", out nugetFeedId)) { Log.Debug("Finding NuGet feed for step {StepName:l}", step.Name); FeedResource feed = null; if (FeedCustomExpressionHelper.IsRealFeedId(nugetFeedId.Value)) { feed = await Repository.Feeds.Get(nugetFeedId.Value).ConfigureAwait(false); } else { feed = FeedCustomExpressionHelper.CustomExpressionFeedWithId(nugetFeedId.Value); } if (feed == null) { throw new CouldNotFindException("NuGet feed for step", step.Name); } if (nugetFeeds.All(f => f.Id != nugetFeedId.Value)) { nugetFeeds.Add(new ReferenceDataItem(feed.Id, feed.Name)); } } } } Log.Debug("Finding action templates for project"); var actionTemplates = new List <ReferenceDataItem>(); foreach (var step in deploymentProcess.Steps) { foreach (var action in step.Actions) { PropertyValueResource templateId; if (action.Properties.TryGetValue("Octopus.Action.Template.Id", out templateId)) { Log.Debug("Finding action template for step {StepName:l}", step.Name); var template = await actionTemplateRepository.Get(templateId.Value).ConfigureAwait(false); if (template == null) { throw new CouldNotFindException("action template for step", step.Name); } if (actionTemplates.All(t => t.Id != templateId.Value)) { actionTemplates.Add(new ReferenceDataItem(template.Id, template.Name)); } } } } var libraryVariableSets = new List <ReferenceDataItem>(); foreach (var libraryVariableSetId in project.IncludedLibraryVariableSetIds) { var libraryVariableSet = await Repository.LibraryVariableSets.Get(libraryVariableSetId).ConfigureAwait(false); if (libraryVariableSet == null) { throw new CouldNotFindException("library variable set with Id", libraryVariableSetId); } libraryVariableSets.Add(new ReferenceDataItem(libraryVariableSet.Id, libraryVariableSet.Name)); } LifecycleResource lifecycle = null; if (project.LifecycleId != null) { lifecycle = await Repository.Lifecycles.Get(project.LifecycleId).ConfigureAwait(false); if (lifecycle == null) { throw new CouldNotFindException($"lifecycle with Id {project.LifecycleId} for project ", project.Name); } } var export = new ProjectExport { Project = project, ProjectGroup = new ReferenceDataItem(projectGroup.Id, projectGroup.Name), VariableSet = variables, DeploymentProcess = deploymentProcess, NuGetFeeds = nugetFeeds, ActionTemplates = actionTemplates, LibraryVariableSets = libraryVariableSets, Lifecycle = lifecycle != null ? new ReferenceDataItem(lifecycle.Id, lifecycle.Name) : null, Channels = channels.ToList(), ChannelLifecycles = channelLifecycles, }; var metadata = new ExportMetadata { ExportedAt = DateTime.Now, OctopusVersion = Repository.Client.RootDocument.Version, Type = typeof(ProjectExporter).GetAttributeValue((ExporterAttribute ea) => ea.Name), ContainerType = typeof(ProjectExporter).GetAttributeValue((ExporterAttribute ea) => ea.EntityType) }; FileSystemExporter.Export(FilePath, metadata, export); }
public async Task OpenAsync( string databaseName, ContainerProperties collection, IReadOnlyList <PartitionKeyRangeIdentity> partitionKeyRangeIdentities, CancellationToken cancellationToken) { List <Task <DocumentServiceResponse> > tasks = new List <Task <DocumentServiceResponse> >(); int batchSize = GatewayAddressCache.DefaultBatchSize; #if !(NETSTANDARD15 || NETSTANDARD16) #if NETSTANDARD20 // GetEntryAssembly returns null when loaded from native netstandard2.0 if (System.Reflection.Assembly.GetEntryAssembly() != null) { #endif int userSpecifiedBatchSize = 0; if (int.TryParse(System.Configuration.ConfigurationManager.AppSettings[GatewayAddressCache.AddressResolutionBatchSize], out userSpecifiedBatchSize)) { batchSize = userSpecifiedBatchSize; } #if NETSTANDARD20 } #endif #endif string collectionAltLink = string.Format(CultureInfo.InvariantCulture, "{0}/{1}/{2}/{3}", Paths.DatabasesPathSegment, Uri.EscapeUriString(databaseName), Paths.CollectionsPathSegment, Uri.EscapeUriString(collection.Id)); using (DocumentServiceRequest request = DocumentServiceRequest.CreateFromName( OperationType.Read, collectionAltLink, ResourceType.Collection, AuthorizationTokenType.PrimaryMasterKey)) { for (int i = 0; i < partitionKeyRangeIdentities.Count; i += batchSize) { tasks.Add(this.GetServerAddressesViaGatewayAsync( request, collection.ResourceId, partitionKeyRangeIdentities.Skip(i).Take(batchSize).Select(range => range.PartitionKeyRangeId), false)); } } foreach (DocumentServiceResponse response in await Task.WhenAll(tasks)) { using (response) { FeedResource <Address> addressFeed = response.GetResource <FeedResource <Address> >(); bool inNetworkRequest = this.IsInNetworkRequest(response); IEnumerable <Tuple <PartitionKeyRangeIdentity, PartitionAddressInformation> > addressInfos = addressFeed.Where(addressInfo => ProtocolFromString(addressInfo.Protocol) == this.protocol) .GroupBy(address => address.PartitionKeyRangeId, StringComparer.Ordinal) .Select(group => this.ToPartitionAddressAndRange(collection.ResourceId, @group.ToList(), inNetworkRequest)); foreach (Tuple <PartitionKeyRangeIdentity, PartitionAddressInformation> addressInfo in addressInfos) { this.serverPartitionAddressCache.Set( new PartitionKeyRangeIdentity(collection.ResourceId, addressInfo.Item1.PartitionKeyRangeId), addressInfo.Item2); } } } }
protected override Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { List <Address> addresses = new List <Address>() { new Address() { IsPrimary = true, PhysicalUri = "https://blabla.com", Protocol = RuntimeConstants.Protocols.HTTPS, PartitionKeyRangeId = "YxM9ANCZIwABAAAAAAAAAA==" }, new Address() { IsPrimary = false, PhysicalUri = "https://blabla3.com", Protocol = RuntimeConstants.Protocols.HTTPS, PartitionKeyRangeId = "YxM9ANCZIwABAAAAAAAAAA==" }, new Address() { IsPrimary = false, PhysicalUri = "https://blabla2.com", Protocol = RuntimeConstants.Protocols.HTTPS, PartitionKeyRangeId = "YxM9ANCZIwABAAAAAAAAAA==" }, }; if (this.returnFullReplicaSet) { addresses.Add(new Address() { IsPrimary = false, PhysicalUri = "https://blabla4.com", Protocol = RuntimeConstants.Protocols.HTTPS, PartitionKeyRangeId = "YxM9ANCZIwABAAAAAAAAAA==" }); this.returnFullReplicaSet = false; } else { this.returnFullReplicaSet = true; } if (this.returnUpdatedAddresses) { addresses.RemoveAll(address => address.IsPrimary == true); addresses.Add(new Address() { IsPrimary = true, PhysicalUri = "https://blabla5.com", Protocol = RuntimeConstants.Protocols.HTTPS, PartitionKeyRangeId = "YxM9ANCZIwABAAAAAAAAAA==" }); this.returnUpdatedAddresses = false; } else { this.returnUpdatedAddresses = true; } FeedResource <Address> addressFeedResource = new FeedResource <Address>() { Id = "YxM9ANCZIwABAAAAAAAAAA==", SelfLink = "dbs/YxM9AA==/colls/YxM9ANCZIwA=/docs/YxM9ANCZIwABAAAAAAAAAA==/", Timestamp = DateTime.Now, InnerCollection = new Collection <Address>(addresses), }; StringBuilder feedResourceString = new StringBuilder(); addressFeedResource.SaveTo(feedResourceString); StringContent content = new StringContent(feedResourceString.ToString()); HttpResponseMessage responseMessage = new HttpResponseMessage() { StatusCode = HttpStatusCode.OK, Content = content, }; if (this.Headers != null) { foreach (KeyValuePair <string, string> headerPair in this.Headers) { responseMessage.Headers.Add(headerPair.Key, headerPair.Value); } } return(Task.FromResult <HttpResponseMessage>(responseMessage)); }
private static void CreateDeploymentProcess(IOctopusRepository repository, ProjectResource project, FeedResource feed) { var deploymentProcess = repository.DeploymentProcesses.Get(project.DeploymentProcessId); CreateVariable(repository, project, "serverInstance", @".\SQL2012"); CreateVariable(repository, project, "password", "Redg@te1", true); deploymentProcess.Steps.Add(new DeploymentStepResource { Name = "Download and extract database package", Condition = DeploymentStepCondition.Success, Properties = { { "Octopus.Action.TargetRoles", "database" } }, Actions = { new DeploymentActionResource { ActionType = "Octopus.TentaclePackage", Name = "Database package", Properties = { { SpecialVariables.Action.Package.NuGetPackageId, "SimpleTalkDatabase" }, { SpecialVariables.Action.Package.NuGetFeedId, feed.Id }, { SpecialVariables.Action.Package.AutomaticallyRunConfigurationTransformationFiles, "False" }, { SpecialVariables.Action.Package.AutomaticallyUpdateAppSettingsAndConnectionStrings, "False" } } } } }); deploymentProcess.Steps.Add(new DeploymentStepResource { Name = "Step A", Condition = DeploymentStepCondition.Success, Properties = { { "Octopus.Action.TargetRoles", "database" } }, Actions = { new DeploymentActionResource { ActionType = "Octopus.Script", Name = "Say Hello", Properties = { { SpecialVariables.Action.Script.ScriptBody, "Write-Host 'Hello'" } } } } }); repository.DeploymentProcesses.Modify(deploymentProcess); }
public void Setup() { // setup data objects channelVersionRules = new List <ChannelVersionRuleResource>(); projectResource = new ProjectResource { DeploymentProcessId = TestHelpers.GetId("deploymentprocess"), Id = TestHelpers.GetId("project") }; deploymentProcessResource = new DeploymentProcessResource { ProjectId = projectResource.Id, Id = projectResource.DeploymentProcessId }; releaseTemplateResource = new ReleaseTemplateResource { DeploymentProcessId = projectResource.DeploymentProcessId, Packages = new List <ReleaseTemplatePackage>(), Id = TestHelpers.GetId("releaseTemplate") }; channelResource = new ChannelResource { IsDefault = true, Id = TestHelpers.GetId("channel"), ProjectId = projectResource.Id, Rules = channelVersionRules, Name = TestHelpers.GetId("channelname") }; feedResource = new FeedResource { Id = BuiltInFeedId, Name = "Built in feed", Links = new LinkCollection { { "SearchTemplate", TestHelpers.GetId("searchUri") } } }; // setup mocks logger = Substitute.For <ILogger>(); versionResolver = Substitute.For <IPackageVersionResolver>(); versionRuleTester = Substitute.For <IChannelVersionRuleTester>(); commandOutputProvider = Substitute.For <ICommandOutputProvider>(); deploymentProcessRepository = Substitute.For <IDeploymentProcessRepository>(); deploymentProcessRepository.Get(projectResource.DeploymentProcessId) .Returns(Task.FromResult(deploymentProcessResource)); deploymentProcessRepository .GetTemplate(Arg.Is(deploymentProcessResource), Arg.Is(channelResource)) .Returns(Task.FromResult(releaseTemplateResource)); versionRuleTester .Test(Arg.Any <IOctopusAsyncRepository>(), Arg.Any <ChannelVersionRuleResource>(), Arg.Any <string>(), Arg.Any <string>()) .Returns(Task.FromResult(channelVersionRuleTestResult)); deploymentProcessRepositoryBeta = Substitute.For <IDeploymentProcessRepositoryBeta>(); deploymentProcessRepositoryBeta.Get(projectResource, Arg.Any <string>()) .Returns(Task.FromResult(deploymentProcessResource)); var feeds = new List <FeedResource> { feedResource }; releaseRepository = Substitute.For <IReleaseRepository>(); feedRepository = Substitute.For <IFeedRepository>(); feedRepository.Get(Arg.Any <string[]>()).Returns(feeds); feedRepository.FindByNames(Arg.Any <IEnumerable <string> >()).Returns(feeds); repository = Substitute.For <IOctopusAsyncRepository>(); repository.DeploymentProcesses.Returns(deploymentProcessRepository); repository.DeploymentProcesses.Beta().Returns(deploymentProcessRepositoryBeta); repository.Releases.Returns(releaseRepository); repository.Feeds.Returns(feedRepository); repository.Client .Get <List <PackageResource> >(Arg.Any <string>(), Arg.Any <IDictionary <string, object> >()) .Returns(packages); builder = new ReleasePlanBuilder(logger, versionResolver, versionRuleTester, commandOutputProvider); gitReference = null; }