public override int Run(string[] remainingArguments) { var api = string.IsNullOrEmpty(_teamCityAuthToken) ? new TeamCityApi(ServerName) : new TeamCityApi(ServerName,_teamCityAuthToken); var buildPackageCache = string.IsNullOrEmpty(_buildPackageCacheFile) ? null : new PackageBuildMappingCache(_buildPackageCacheFile); var resolver = new AggregateBuildDeltaResolver(api, CreateExternalIssueResolvers(), new PackageChangeComparator(),buildPackageCache, new List<NuGetPackageChange>()); ChangeManifest = string.IsNullOrEmpty(BuildType) ? resolver.CreateChangeManifestFromBuildTypeName(ProjectName, BuildName,_referenceBuild, _from, _to, _useBuildSystemIssueResolution, _recurse) : resolver.CreateChangeManifestFromBuildTypeId(BuildType, _referenceBuild, _from, _to, _useBuildSystemIssueResolution, _recurse); OutputChanges(CreateOutputRenderers(), new List<Action<string>> {Console.Write, a => { if (!string.IsNullOrEmpty(OutputFileName)) File.WriteAllText(OutputFileName, a); }}); return 0; }
public static AggregateBuildDeltaResolver CreateMockedAggregateBuildDeltaResolver(IEnumerable<BuildTemplate> buildTemplates) { const string apiServer = "http://test.server"; var api = A.Fake<ITeamCityApi>(); A.CallTo(() => api.Url).Returns(apiServer); var packageCache = new PackageBuildMappingCache(); var issueResolver = A.Fake<IExternalIssueResolver>(); foreach (var template in buildTemplates) { SetExpectations(template, api, issueResolver, packageCache); } var resolver = new AggregateBuildDeltaResolver(api, new IssueDetailResolver(new[] {issueResolver}), new PackageChangeComparator(), packageCache, new ConcurrentBag<NuGetPackageChange>()); return resolver; }
public override int Run(string[] remainingArguments) { ICacheClient client = new MemoryCacheClient(); var api = new TeamCityApi(new CachingThreadSafeAuthenticatedRestClient(new MemoryCacheClient(), _serverName, _teamCityAuthToken), client); var buildPackageCache = string.IsNullOrEmpty(_buildPackageCacheFile) ? null : new PackageBuildMappingCache(_buildPackageCacheFile); var issueDetailResolver = new IssueDetailResolver(CreateExternalIssueResolvers()); var resolver = new AggregateBuildDeltaResolver(api, issueDetailResolver, new PackageChangeComparator(), buildPackageCache, new ConcurrentBag<NuGetPackageChange>()); _changeManifest = string.IsNullOrEmpty(_buildType) ? resolver.CreateChangeManifestFromBuildTypeName(_projectName, _buildName,_referenceBuild, _from, _to, _useBuildSystemIssueResolution, _recurse, _branchName) : resolver.CreateChangeManifestFromBuildTypeId(_buildType, _referenceBuild, _from, _to, _useBuildSystemIssueResolution, _recurse, _branchName); OutputChanges(CreateOutputRenderers(), new List<Action<string>> {Console.Write, a => { if (!string.IsNullOrEmpty(_outputFileName)) File.WriteAllText(_outputFileName, a); }}); return 0; }
public override int Run(string[] remainingArguments) { var api = string.IsNullOrEmpty(_teamCityAuthToken) ? new TeamCityApi(ServerName) : new TeamCityApi(ServerName, _teamCityAuthToken); var buildPackageCache = string.IsNullOrEmpty(_buildPackageCacheFile) ? null : new PackageBuildMappingCache(_buildPackageCacheFile); var resolver = new AggregateBuildDeltaResolver(api, CreateExternalIssueResolvers(), new PackageChangeComparator(), buildPackageCache, new List <NuGetPackageChange>()); ChangeManifest = string.IsNullOrEmpty(BuildType) ? resolver.CreateChangeManifestFromBuildTypeName(ProjectName, BuildName, _referenceBuild, _from, _to, _useBuildSystemIssueResolution, _recurse) : resolver.CreateChangeManifestFromBuildTypeId(BuildType, _referenceBuild, _from, _to, _useBuildSystemIssueResolution, _recurse); OutputChanges(CreateOutputRenderers(), new List <Action <string> > { Console.Write, a => { if (!string.IsNullOrEmpty(OutputFileName)) { File.WriteAllText(OutputFileName, a); } } }); return(0); }
private ChangeManifest CreateChangeManifest(string buildName, string buildType, string referenceBuild = null, string from = null, string to = null, string projectName = null, bool useBuildSystemIssueResolution = true, bool recurse = false) { var changeManifest = new ChangeManifest(); if (recurse && _packageBuildMappingCache == null) { changeManifest.GenerationLog.Add(new LogEntry(DateTime.Now, Status.Warning, "Recurse option provided with no PackageBuildMappingCache, we will not be honoring the Recurse option.")); changeManifest.GenerationStatus = Status.Warning; } buildType = buildType ?? ResolveBuildTypeId(projectName, buildName); if (String.IsNullOrEmpty(from)) { changeManifest.GenerationLog.Add(new LogEntry(DateTime.Now, Status.Warning, "Resolving FROM version based on the provided BuildType (FROM was not provided).")); from = ResolveFromVersion(buildType); } if (String.IsNullOrEmpty(to)) { changeManifest.GenerationLog.Add(new LogEntry(DateTime.Now, Status.Warning, "Resolving TO version based on the provided BuildType (TO was not provided).")); to = ResolveToVersion(buildType); } var buildWithCommitData = referenceBuild ?? buildType; var buildTypeDetails = _api.GetBuildTypeDetailsById(buildType); var referenceBuildTypeDetails = !String.IsNullOrEmpty(referenceBuild) ? _api.GetBuildTypeDetailsById(referenceBuild) : null; if (!String.IsNullOrEmpty(from) && !String.IsNullOrEmpty(to) && !String.IsNullOrEmpty(buildWithCommitData)) { changeManifest.GenerationLog.Add(new LogEntry(DateTime.Now, Status.Ok, "Getting builds based on BuildType")); var builds = _api.GetBuildsByBuildType(buildWithCommitData); if (builds != null) { var buildList = builds as List <Build> ?? builds.ToList(); changeManifest.GenerationLog.Add(new LogEntry(DateTime.Now, Status.Ok, string.Format("Got {0} builds for BuildType {1}.", buildList.Count(), buildType))); var changeDetails = _api.GetChangeDetailsByBuildTypeAndBuildNumber(buildWithCommitData, @from, to, buildList).ToList(); var issueDetailResolver = new IssueDetailResolver(_externalIssueResolvers); //Rather than use TeamCity to resolve the issue to commit details (via TeamCity plugins) use the issue resolvers directly... var issues = useBuildSystemIssueResolution ? _api.GetIssuesByBuildTypeAndBuildRange(buildWithCommitData, @from, to, buildList).ToList() : issueDetailResolver.GetAssociatedIssues(changeDetails).ToList(); changeManifest.GenerationLog.Add(new LogEntry(DateTime.Now, Status.Ok, string.Format("Got {0} issues for BuildType {1}.", issues.Count(), buildType))); changeManifest.GenerationLog.Add(new LogEntry(DateTime.Now, Status.Ok, "Checking package dependencies.")); var buildFrom = buildList.FirstOrDefault(b => b.Number == @from); var buildTo = buildList.FirstOrDefault(b => b.Number == to); var initialPackages = new List <TeamCityApi.PackageDetails>(); var finalPackages = new List <TeamCityApi.PackageDetails>(); if (buildFrom != null) { initialPackages = _api.GetNuGetDependenciesByBuildTypeAndBuildId(buildType, buildFrom.Id).ToList(); } if (buildTo != null) { finalPackages = _api.GetNuGetDependenciesByBuildTypeAndBuildId(buildType, buildTo.Id).ToList(); } var packageChanges = _packageChangeComparator.GetPackageChanges(initialPackages, finalPackages).ToList(); var issueDetails = issueDetailResolver.GetExternalIssueDetails(issues); changeManifest.NuGetPackageChanges = packageChanges; changeManifest.ChangeDetails.AddRange(changeDetails); changeManifest.IssueDetails.AddRange(issueDetails); changeManifest.Generated = DateTime.Now; changeManifest.FromVersion = @from; changeManifest.ToVersion = to; changeManifest.BuildConfiguration = buildTypeDetails; changeManifest.ReferenceBuildConfiguration = referenceBuildTypeDetails ?? new BuildTypeDetails(); } else { changeManifest.GenerationLog.Add(new LogEntry(DateTime.Now, Status.Warning, string.Format("No builds returned for BuildType {0}.", buildType))); } } //Now we need to see if we need to recurse, and whether we have been given a cache file.... if (changeManifest.NuGetPackageChanges.Any() && recurse && _packageBuildMappingCache != null) { foreach (var dependency in changeManifest.NuGetPackageChanges.Where(c => c.Type == NuGetPackageChangeType.Modified)) { var traversedDependency = _traversedPackageChanges.FirstOrDefault(p => p.NewVersion == dependency.NewVersion && p.OldVersion == dependency.OldVersion && p.PackageId == dependency.PackageId); if (traversedDependency != null) { dependency.ChangeManifest = traversedDependency.ChangeManifest; continue; } var mappings = _packageBuildMappingCache.PackageBuildMappings.Where(m => m.PackageId.Equals(dependency.PackageId, StringComparison.CurrentCultureIgnoreCase)).ToList(); PackageBuildMapping build = null; if (mappings.Count == 1) { //We only got one back, this is good... build = mappings.First(); changeManifest.GenerationLog.Add(new LogEntry(DateTime.Now, Status.Ok, string.Format("Found singular packages to build mapping {0}.", build.BuildConfigurationName))); } else if (mappings.Any()) { //Ok, so multiple builds are outputting this package, so we need to try and constrain on project... build = mappings.FirstOrDefault(m => m.Project.Equals(buildTypeDetails.Project.Name, StringComparison.OrdinalIgnoreCase)); if (build != null) { changeManifest.GenerationLog.Add(new LogEntry(DateTime.Now, Status.Warning, string.Format("Found duplicate mappings, using package to build mapping {0}.", build.BuildConfigurationName))); } } if (build != null) { if (build.BuildConfigurationId == buildType) { continue; } var instanceTeamCityApi = _api.TeamCityServer.Equals(build.ServerUrl, StringComparison.OrdinalIgnoreCase) ? _api : new TeamCityApi(build.ServerUrl); var resolver = new AggregateBuildDeltaResolver(instanceTeamCityApi, _externalIssueResolvers, _packageChangeComparator, _packageBuildMappingCache, _traversedPackageChanges); var dependencyManifest = resolver.CreateChangeManifest(null, build.BuildConfigurationId, null, dependency.OldVersion, dependency.NewVersion, null, true, true); dependency.ChangeManifest = dependencyManifest; } else { changeManifest.GenerationLog.Add(new LogEntry(DateTime.Now, Status.Warning, string.Format("Did not find a mapping for package: {0}.", dependency.PackageId))); } _traversedPackageChanges.Add(dependency); } } return(changeManifest); }
private ChangeManifest CreateChangeManifest(string buildName, string buildType, string referenceBuild = null, string from = null, string to = null, string projectName = null, bool useBuildSystemIssueResolution = true, bool recurse = false) { var changeManifest = new ChangeManifest(); if (recurse && _packageBuildMappingCache == null) { changeManifest.GenerationLog.Add(new LogEntry(DateTime.Now,Status.Warning,"Recurse option provided with no PackageBuildMappingCache, we will not be honoring the Recurse option.")); changeManifest.GenerationStatus = Status.Warning; } buildType = buildType ?? ResolveBuildTypeId(projectName, buildName); if (String.IsNullOrEmpty(from)) { changeManifest.GenerationLog.Add(new LogEntry(DateTime.Now, Status.Warning, "Resolving FROM version based on the provided BuildType (FROM was not provided).")); from = ResolveFromVersion(buildType); } if (String.IsNullOrEmpty(to)) { changeManifest.GenerationLog.Add(new LogEntry(DateTime.Now, Status.Warning, "Resolving TO version based on the provided BuildType (TO was not provided).")); to = ResolveToVersion(buildType); } var buildWithCommitData = referenceBuild ?? buildType; var buildTypeDetails = _api.GetBuildTypeDetailsById(buildType); var referenceBuildTypeDetails = !String.IsNullOrEmpty(referenceBuild) ? _api.GetBuildTypeDetailsById(referenceBuild) : null; if (!String.IsNullOrEmpty(from) && !String.IsNullOrEmpty(to) && !String.IsNullOrEmpty(buildWithCommitData)) { changeManifest.GenerationLog.Add(new LogEntry(DateTime.Now, Status.Ok, "Getting builds based on BuildType")); var builds = _api.GetBuildsByBuildType(buildWithCommitData); if (builds != null) { var buildList = builds as List<Build> ?? builds.ToList(); changeManifest.GenerationLog.Add(new LogEntry(DateTime.Now,Status.Ok, string.Format("Got {0} builds for BuildType {1}.",buildList.Count(), buildType))); var changeDetails =_api.GetChangeDetailsByBuildTypeAndBuildNumber(buildWithCommitData, @from, to, buildList).ToList(); var issueDetailResolver = new IssueDetailResolver(_externalIssueResolvers); //Rather than use TeamCity to resolve the issue to commit details (via TeamCity plugins) use the issue resolvers directly... var issues = useBuildSystemIssueResolution ? _api.GetIssuesByBuildTypeAndBuildRange(buildWithCommitData, @from, to, buildList).ToList() : issueDetailResolver.GetAssociatedIssues(changeDetails).ToList(); changeManifest.GenerationLog.Add(new LogEntry(DateTime.Now,Status.Ok, string.Format("Got {0} issues for BuildType {1}.", issues.Count(),buildType))); changeManifest.GenerationLog.Add(new LogEntry(DateTime.Now, Status.Ok, "Checking package dependencies.")); var buildFrom = buildList.FirstOrDefault(b => b.Number == @from); var buildTo = buildList.FirstOrDefault(b => b.Number == to); var initialPackages = new List<TeamCityApi.PackageDetails>(); var finalPackages = new List<TeamCityApi.PackageDetails>(); if (buildFrom != null) initialPackages = _api.GetNuGetDependenciesByBuildTypeAndBuildId(buildType,buildFrom.Id).ToList(); if (buildTo != null) finalPackages = _api.GetNuGetDependenciesByBuildTypeAndBuildId(buildType, buildTo.Id).ToList(); var packageChanges = _packageChangeComparator.GetPackageChanges(initialPackages, finalPackages).ToList(); var issueDetails = issueDetailResolver.GetExternalIssueDetails(issues); changeManifest.NuGetPackageChanges = packageChanges; changeManifest.ChangeDetails.AddRange(changeDetails); changeManifest.IssueDetails.AddRange(issueDetails); changeManifest.Generated = DateTime.Now; changeManifest.FromVersion = @from; changeManifest.ToVersion = to; changeManifest.BuildConfiguration = buildTypeDetails; changeManifest.ReferenceBuildConfiguration = referenceBuildTypeDetails ?? new BuildTypeDetails(); } else { changeManifest.GenerationLog.Add(new LogEntry(DateTime.Now, Status.Warning, string.Format("No builds returned for BuildType {0}.", buildType))); } } //Now we need to see if we need to recurse, and whether we have been given a cache file.... if (changeManifest.NuGetPackageChanges.Any() && recurse && _packageBuildMappingCache != null) { foreach (var dependency in changeManifest.NuGetPackageChanges.Where(c => c.Type == NuGetPackageChangeType.Modified)) { var traversedDependency = _traversedPackageChanges.FirstOrDefault(p => p.NewVersion == dependency.NewVersion && p.OldVersion == dependency.OldVersion && p.PackageId == dependency.PackageId); if (traversedDependency != null) { dependency.ChangeManifest = traversedDependency.ChangeManifest; continue; } var mappings = _packageBuildMappingCache.PackageBuildMappings.Where(m => m.PackageId.Equals(dependency.PackageId, StringComparison.CurrentCultureIgnoreCase)).ToList(); PackageBuildMapping build = null; if (mappings.Count == 1) { //We only got one back, this is good... build = mappings.First(); changeManifest.GenerationLog.Add(new LogEntry(DateTime.Now, Status.Ok, string.Format("Found singular packages to build mapping {0}.", build.BuildConfigurationName))); } else if (mappings.Any()) { //Ok, so multiple builds are outputting this package, so we need to try and constrain on project... build = mappings.FirstOrDefault(m => m.Project.Equals(buildTypeDetails.Project.Name, StringComparison.OrdinalIgnoreCase)); if (build != null) changeManifest.GenerationLog.Add(new LogEntry(DateTime.Now, Status.Warning, string.Format("Found duplicate mappings, using package to build mapping {0}.", build.BuildConfigurationName))); } if (build != null) { if (build.BuildConfigurationId == buildType) continue; var instanceTeamCityApi = _api.TeamCityServer.Equals(build.ServerUrl, StringComparison.OrdinalIgnoreCase) ? _api : new TeamCityApi(build.ServerUrl); var resolver = new AggregateBuildDeltaResolver(instanceTeamCityApi, _externalIssueResolvers,_packageChangeComparator,_packageBuildMappingCache, _traversedPackageChanges); var dependencyManifest = resolver.CreateChangeManifest(null, build.BuildConfigurationId, null,dependency.OldVersion,dependency.NewVersion, null, true, true); dependency.ChangeManifest = dependencyManifest; } else { changeManifest.GenerationLog.Add(new LogEntry(DateTime.Now, Status.Warning, string.Format("Did not find a mapping for package: {0}.", dependency.PackageId))); } _traversedPackageChanges.Add(dependency); } } return changeManifest; }