public static async Task <ImmutableArray <Path> > GetPathsAsync(VssConnection connection, string branch, string build, int buildDef, string component, string jsonFile, ILogger logger) { var gitClient = connection.GetClient <GitHttpClient>(); var buildClient = connection.GetClient <BuildHttpClient>(); var allRefs = await gitClient.GetTagRefsAsync(REPO); var nonTempRefs = allRefs.Where(r => !r.Name.Contains("temp")); var correctNamedRefs = nonTempRefs.Where(r => r.Name.Contains($"{branch}/")) .Where(r => r.Name.EndsWith(build)) .ToArray(); if (correctNamedRefs.Length == 0) { logger.LogWarning($"No VS tags found that mateched {branch}/{build}"); } var jsonFilesAtLocation = await Task.WhenAll(correctNamedRefs.Select(async tag => { logger.LogError(tag.Url); var desc = new GitVersionDescriptor(); desc.VersionType = GitVersionType.Tag; desc.Version = tag.Name.Replace("refs/tags/", ""); var componentsStream = await gitClient.GetItemContentAsync(PROJECT, REPO, "/.corext/Configs/components.json", versionDescriptor: desc); var componentsStreamReader = new System.IO.StreamReader(componentsStream, System.Text.Encoding.UTF8); var customStream = await gitClient.GetItemContentAsync(PROJECT, REPO, $"/.corext/Configs/{jsonFile}.json", versionDescriptor: desc); var customStreamReader = new System.IO.StreamReader(customStream, System.Text.Encoding.UTF8); return(new[] { (Tag: tag, JsonSource: await componentsStreamReader.ReadToEndAsync()), (Tag: tag, JsonSource: await customStreamReader.ReadToEndAsync()), });
public async Task TestPull() { var data = File.ReadAllText("SerialisedObjects\\vsts_req.json"); var obj = JsonConvert.DeserializeObject <VstsRequest>(data); var collectionId = AppSettings.AzureDevOpsCollectionName; var connection = new VssConnection(new Uri(collectionId), new VssBasicCredential(string.Empty, SecretOptions.Value.PAT)); var gitClient = connection.GetClient <GitHttpClient>(); var repoId = obj.resource.repository.id; var pr = await gitClient.GetPullRequestAsync(obj.resource.repository.id, obj.resource.pullRequestId); var versionDesc = new GitVersionDescriptor { VersionType = GitVersionType.Branch, Version = obj.resource.sourceRefName.Replace("refs/heads/", "") }; var items = await gitClient.GetItemsAsync(obj.resourceContainers.project.id, obj.resource.repository.id, "/", VersionControlRecursionType.Full, versionDescriptor : versionDesc); foreach (var i in items.Where(_ => !_.IsFolder)) { var content = await gitClient.GetItemAsync(obj.resource.repository.id, i.Path, includeContent : true, versionDescriptor : versionDesc); } }
public void Download(string targetFilePath) { ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; Console.WriteLine($"-----> Downloading file {sourceFileUrlRelativeToTheRoot} into {targetFilePath} from azure devops collection: {collectionUrl}, project: {projectName}, repo: {repoName}"); Directory.CreateDirectory(Path.GetDirectoryName(targetFilePath)); var credentials = new VssCredentials(new VssBasicCredential("", apiToken)); var connection = new VssConnection(collectionUrl, credentials); var client = connection.GetClient <GitHttpClient>(); var repository = client.GetRepositoryAsync(projectName, repoName, string.Empty, default).Result; var descriptor = new GitVersionDescriptor() { Version = "master" }; using (var file = client.GetItemContentAsync(repository.Id, sourceFileUrlRelativeToTheRoot, versionDescriptor: descriptor).Result) { using (var buffer = new MemoryStream()) { file.CopyTo(buffer); File.WriteAllBytes(targetFilePath, buffer.ToArray()); } } }
public override IEnumerable <PSObject> GetLiteralItem(Segment segment, Segment childSegment) { segment.GetProvider().WriteDebug("DriveItems.Projects.Git.Repos.GetLiteralItem(Segment, Segment)"); GitHttpClient httpClient = this.GetHttpClient(segment) as GitHttpClient; return(this.Wrap( segment, () => { GitVersionDescriptor versionDescriptor = new GitVersionDescriptor(); versionDescriptor.Version = SegmentHelper.GetBranchName(segment); versionDescriptor.VersionType = GitVersionType.Branch; return new[] { this.ConvertToChildDriveItem( segment, httpClient .GetItemAsync( project: SegmentHelper.GetProjectName(segment), repositoryId: SegmentHelper.GetRepoName(segment), path: Uri.UnescapeDataString(childSegment.UnescapedName), versionDescriptor: versionDescriptor) .Result) }; })); }
private static async Task <(string branchName, string buildNumber)> TryGetRoslynBranchAndBuildNumberForReleaseAsync( VisualStudioVersion release, GitHttpClient vsGitClient) { GitRepository vsRepository = await GetVSRepositoryAsync(vsGitClient); var commit = new GitVersionDescriptor { VersionType = GitVersionType.Commit, Version = release.CommitSha }; using var componentsJsonStream = await vsGitClient.GetItemContentAsync( vsRepository.Id, @".corext\Configs\dotnetcodeanalysis-components.json", download : true, versionDescriptor : commit); var componentsJsonContents = await new StreamReader(componentsJsonStream).ReadToEndAsync(); var componentsJson = JObject.Parse(componentsJsonContents); var languageServicesUrlAndManifestName = (string)componentsJson["Components"]["Microsoft.CodeAnalysis.LanguageServices"]["url"]; var parts = languageServicesUrlAndManifestName.Split(';'); if (parts.Length != 2) { return(default);
public static async Task <VersionsUpdater> Create(GitHttpClient gitClient, string commitId, List <string> warningMessages) { var vsRepoId = RoslynInsertionTool.VSRepoId; var version = new GitVersionDescriptor { VersionType = GitVersionType.Commit, Version = commitId }; var versionsTemplateContent = await gitClient.GetItemContentAsync(vsRepoId, VersionsTemplatePath, download : true, versionDescriptor : version); using var reader = new StreamReader(versionsTemplateContent); string versionsTemplate = reader.ReadToEnd(); return(new VersionsUpdater(versionsTemplate, warningMessages)); }
private static GitVersionDescriptor MakeVersionDescriptor(SourceInformation searchInformation) { Logger.Trace("Entering"); var output = new GitVersionDescriptor { VersionType = GitVersionType.Branch, Version = searchInformation.GitBranch }; Logger.Trace("Exiting"); return(output); }
public async Task <List <(string path, string contents)> > GetFilesinPR(VstsRequest req) { //var connection = new VssConnection(new Uri(_secrets.Value.VSTSCollection), // new VssBasicCredential(string.Empty, _secrets.Value.PAT)); // var c = connection.AuthenticatedIdentity; var gitClient = _getGitClient(req); var repoId = req.resource.repository.id; var projectId = req.resourceContainers.project.id; var branchRef = req.resource.sourceRefName.Replace("refs/heads/", ""); var versionDesc = new GitVersionDescriptor { VersionType = GitVersionType.Branch, Version = branchRef }; try { var items = await gitClient.GetItemsAsync(projectId, repoId, "/", VersionControlRecursionType.Full, versionDescriptor : versionDesc); var result = new List <(string path, string contents)>(); foreach (var i in items.Where(_ => !_.IsFolder)) { if (i.Path.ToLower().IndexOf("gitignore", StringComparison.Ordinal) != -1) { continue; } var content = await gitClient.GetItemAsync(repoId, i.Path, includeContent : true, versionDescriptor : versionDesc); result.Add((i.Path, content.Content.ToString())); } return(result); } catch (Exception ex) { _logService.TrackException(ex); } return(new List <(string path, string contents)>()); }
static void Main(string[] args) { var credentials = new VssAadCredential(); var messageHandler = new VssHttpMessageHandler(credentials, new VssHttpRequestSettings()); Uri uri = new Uri(@"https://microsoft.visualstudio.com/"); GitHttpClient gitHttpClient = new GitHttpClient(uri, messageHandler.Credentials); var Repositories = gitHttpClient.GetRepositoriesAsync().Result; GitRepository repository = Repositories.FirstOrDefault(r => r.Name.ToLowerInvariant() == "Localization".ToLowerInvariant()); var gitBranchStatuss = gitHttpClient.GetBranchesAsync(repository.Id).Result; GitBranchStats gitBranchStatus = gitBranchStatuss.FirstOrDefault(branch => branch.Name.ToLowerInvariant() == "master"); var descriptor = new GitVersionDescriptor() { Version = gitBranchStatus.Name, VersionOptions = GitVersionOptions.None, VersionType = GitVersionType.Branch }; //GitItem item = gitHttpClient.GetItemAsync(repositoryId: repository.Id, path: "/intl/af-za/loc/windows/lcl/aad/brokerplugin/microsoft.aad.brokerplugin.dll.lcl", scopePath: "/intl/af-za/loc/windows/lcl/aad/brokerplugin/microsoft.aad.brokerplugin.dll.lcl", recursionLevel: VersionControlRecursionType.OneLevel, includeContentMetadata: true, latestProcessedChange: true, download: true, versionDescriptor: descriptor, userState: null, cancellationToken: new CancellationToken()).Result; VersionControlProjectInfo vvvvvv = new VersionControlProjectInfo(); List <GitItem> items = gitHttpClient.GetItemsAsync(repositoryId: repository.Id, scopePath: "/intl/af-za/loc/windows/lcl/aad/brokerplugin/microsoft.aad.brokerplugin.dll.lcl", recursionLevel: VersionControlRecursionType.OneLevel, includeContentMetadata: true, latestProcessedChange: true, download: true, includeLinks: false, versionDescriptor: descriptor, userState: null, cancellationToken: new CancellationToken()).Result; List <GitCommitRef> aaaa = gitHttpClient.GetCommitsAsync(repositoryId: repository.Id, searchCriteria: new GitQueryCommitsCriteria(), skip: null, top: null, userState: null, cancellationToken: new CancellationToken()).Result; GitCommitChanges gitCommitChanges = gitHttpClient.GetChangesAsync(items[0].CommitId, repositoryId: repository.Id, top: null, skip: null, userState: null, cancellationToken: new CancellationToken()).Result; Stream ssss = gitHttpClient.GetItemContentAsync(repositoryId: repository.Id, path: items[0].Path, recursionLevel: VersionControlRecursionType.None, includeContentMetadata: true, latestProcessedChange: true, download: true, versionDescriptor: descriptor, userState: null, cancellationToken: new CancellationToken()).Result; using (MemoryStream memoryStream = new MemoryStream()) { ssss.CopyTo(memoryStream); // Use StreamReader to read MemoryStream created from byte array using (StreamReader streamReader = new StreamReader(new MemoryStream(memoryStream.ToArray()))) { string fileString = streamReader.ReadToEnd(); } } }
private static async Task <RoslynBuildInformation?> TryGetRoslynBuildForReleaseAsync(VisualStudioVersion release, GitHttpClient gitClient, BuildHttpClient buildClient) { var commit = new GitVersionDescriptor { VersionType = GitVersionType.Commit, Version = release.CommitSha }; GitRepository vsRepository = await GetVSRepositoryAsync(gitClient); using var componentsJsonStream = await gitClient.GetItemContentAsync( vsRepository.Id, @".corext\Configs\dotnetcodeanalysis-components.json", download : true, versionDescriptor : commit); var fileContents = await new StreamReader(componentsJsonStream).ReadToEndAsync(); var componentsJson = JObject.Parse(fileContents); var languageServicesUrlAndManifestName = (string)componentsJson["Components"]["Microsoft.CodeAnalysis.LanguageServices"]["url"]; var parts = languageServicesUrlAndManifestName.Split(';'); if (parts.Length != 2) { return(null); } if (!parts[1].EndsWith(".vsman")) { return(null); } var buildNumber = new Uri(parts[0]).Segments.Last(); var buildDefinition = (await buildClient.GetDefinitionsAsync(vsRepository.ProjectReference.Id, name: "Roslyn-Signed")).Single(); var build = (await buildClient.GetBuildsAsync(buildDefinition.Project.Id, definitions: new[] { buildDefinition.Id }, buildNumber: buildNumber)).SingleOrDefault(); if (build == null) { return(null); } var buildId = buildDefinition.Name + "_" + build.BuildNumber; return(new RoslynBuildInformation(commitSha: build.SourceVersion, build.SourceBranch.Replace("refs/heads/", ""), buildId)); }
public List <GitCommitRef> GetCommitsReachableFromACommitAndInPath() { GitRepository repo = GitSampleHelpers.FindAnyRepositoryOnAnyProject(this.Context); string branchName = repo.DefaultBranch; string branchNameWithoutRefsHeads = branchName.Remove(0, "refs/heads/".Length); GitVersionDescriptor tipCommitDescriptor = new GitVersionDescriptor() { VersionType = GitVersionType.Branch, VersionOptions = GitVersionOptions.None, Version = branchNameWithoutRefsHeads }; return(this.Context.Connection.GetClient <GitHttpClient>() .GetCommitsAsync(repo.Id, new GitQueryCommitsCriteria() { CompareVersion = tipCommitDescriptor, ItemVersion = m_oldestDescriptor, ItemPath = "/README.md", }).Result); }
public override IEnumerable <PSObject> GetItems(Segment segment) { segment.GetProvider().WriteDebug("DriveItems.Projects.Git.Items.GetItems(Segment)"); GitHttpClient httpClient = this.GetHttpClient(segment) as GitHttpClient; return(this.Wrap( segment, () => { GitVersionDescriptor versionDescriptor = new GitVersionDescriptor(); versionDescriptor.Version = SegmentHelper.GetBranchName(segment); versionDescriptor.VersionType = GitVersionType.Branch; return httpClient .GetItemsAsync( project: SegmentHelper.GetProjectName(segment), repositoryId: SegmentHelper.GetRepoName(segment), recursionLevel: VersionControlRecursionType.Full, versionDescriptor: versionDescriptor) .Result .Select(x => this.ConvertToChildDriveItem(segment, x)) .ToArray(); })); }
private object GetFirstReleaseBranchByCommit(Guid repoId, GitCommitRef lastCommit, List <GitRef> releaseBranches) { foreach (var releaseBranch in releaseBranches) { var newBranchVersionDescriptor = new GitVersionDescriptor() { VersionType = GitVersionType.Branch, Version = AzureGitHelper.WithoutRefsAndHeadsPrefix(releaseBranch.Name) }; var criteria = new GitQueryCommitsCriteria() { Ids = new List <string>() { lastCommit.CommitId }, Top = 1, ItemVersion = newBranchVersionDescriptor }; if (gitClient.GetCommitsAsync(repoId, criteria, top: 1).Result.Any()) { return(releaseBranch); } } return(null); }
public void Run() { Console.WriteLine($"Retaining builds from [{_options.BuildQueueName}] for component [{_options.ComponentName}]."); var stopwatch = Stopwatch.StartNew(); Console.WriteLine("Getting KeyVault secret..."); var password = GetSecret(Settings.Default.VsoSecretName, _options).Result; var uri = new Uri(Settings.Default.VSTSUrl); var connection = new VssConnection(uri, new WindowsCredential(new NetworkCredential(Settings.Default.UserName, password))); Console.WriteLine("Authenticating connection..."); using (var gitHttpClient = connection.GetClient <GitHttpClient>()) { Console.WriteLine("Finding repository..."); var allRepos = gitHttpClient.GetRepositoriesAsync().Result; var vsRepos = allRepos.Where(r => r.Name == Settings.Default.RepositoryName && r.ProjectReference.Name == Settings.Default.TFSProjectName).ToList(); if (vsRepos.Count != 1) { Console.WriteLine($"Expected to find one repository matching {Settings.Default.TFSProjectName}/{Settings.Default.RepositoryName} but found {vsRepos.Count}."); Environment.Exit(1); } var vsRepo = vsRepos.Single(); var vsRepoGuid = vsRepo.Id; Console.WriteLine("Getting all tags..."); var tagRefs = gitHttpClient.GetTagRefsAsync(vsRepoGuid).Result; var allTagData = ReadCachedTags(); (int numSkipped, int numProcessed, int numFailed, int numCached)operationTracker = (0, 0, 0, 0); Console.WriteLine(); Console.WriteLine($"Processing {tagRefs.Count} tags..."); Parallel.ForEach(tagRefs, (tagRef) => { try { TagData tag; if (allTagData.TryGetValue(tagRef.Name, out tag) && tag.ObjectId == tagRef.ObjectId) { Interlocked.Increment(ref operationTracker.numCached); // We already have the tag and it's data. Let's recheck if it's been expired if (tag.MaybeExists) { tag.MaybeExists = Directory.Exists(tag.RawDropPath); } return; } tag = new TagData(); tag.TagName = tagRef.Name; if (!Regex.IsMatch(tagRef.Name, @"refs/tags/drop/.*/official\.\d{5}.\d{2}") && !tag.IsRelease()) { Interlocked.Increment(ref operationTracker.numSkipped); return; } tag.ObjectId = tagRef.ObjectId; var versionDescriptor = new GitVersionDescriptor() { Version = tagRef.Name.Substring("refs/tags/".Length), VersionOptions = GitVersionOptions.None, VersionType = GitVersionType.Tag }; var annotatedTagDataTask = gitHttpClient.GetAnnotatedTagAsync(Settings.Default.TFSProjectName, vsRepoGuid, tagRef.ObjectId); var annotatedTagData = JObject.Parse(annotatedTagDataTask.Result.Message); tag.RawDropPath = annotatedTagData["RawDropLocation"].Value <string>(); tag.MaybeExists = Directory.Exists(tag.RawDropPath); // If the build is already gone, no reason to get the components.json for it if (tag.MaybeExists) { if (!TryUpdateTag(gitHttpClient, vsRepoGuid, tag, versionDescriptor, @".corext\Configs\components.json") && !TryUpdateTag(gitHttpClient, vsRepoGuid, tag, versionDescriptor, @".corext\Configs\dotnetcodeanalysis-components.json") && !TryUpdateTag(gitHttpClient, vsRepoGuid, tag, versionDescriptor, @".corext\Configs\lutandsbd-components.json") && !TryUpdateTag(gitHttpClient, vsRepoGuid, tag, versionDescriptor, @".corext\Configs\dotnetprojectsystem-components.json")) { throw new Exception("Unable to locate component."); } } if (!allTagData.TryAdd(tagRef.Name, tag)) { throw new Exception("Tag already exists which shouldn't have happened."); } Interlocked.Increment(ref operationTracker.numProcessed); } catch (Exception) { // Catastrophic error: don't cache anything since we have no idea what happened allTagData.TryRemove(tagRef.Name, out _); Interlocked.Increment(ref operationTracker.numFailed); } }); Console.WriteLine($" Processed {operationTracker.numProcessed + operationTracker.numSkipped + operationTracker.numFailed + operationTracker.numCached} tags. {operationTracker.numProcessed} were new, {operationTracker.numSkipped} were skipped, {operationTracker.numFailed} failed to be interpreted, and {operationTracker.numCached} where previously processed."); WriteCachedTags(allTagData); Console.WriteLine(); Console.WriteLine("Locating unique builds..."); // Figure out all our builds that have been inserted, and which release tags if they happen to be release tags var uniqueInsertedBuilds = (from tag in allTagData.Values where tag.MaybeExists group tag by new { tag.InsertedBuildBranch, tag.InsertedBuildNumber } into g select new { g.Key.InsertedBuildBranch, g.Key.InsertedBuildNumber, ReleaseTags = g.Where(t => t.IsRelease()) }) .Distinct().ToList(); Console.WriteLine($" Found {uniqueInsertedBuilds.Count} unique builds."); Console.WriteLine(); var currentBranch = string.Empty; foreach (var insertedBuildsByBranch in uniqueInsertedBuilds.GroupBy(b => b.InsertedBuildBranch)) { Console.WriteLine(insertedBuildsByBranch.Key); foreach (var build in insertedBuildsByBranch.OrderBy(b => b.InsertedBuildNumber)) { Console.Write($" {build.InsertedBuildNumber}"); if (build.ReleaseTags.Any()) { Console.Write($" (released to public as {string.Join(", ", build.ReleaseTags.Select(t => t.TagName).OrderBy(t => t))})"); } Console.WriteLine(); } } using (var buildClient = connection.GetClient <BuildHttpClient>()) { Console.WriteLine("Finding build definition"); var projectId = vsRepo.ProjectReference.Id; var definitions = buildClient.GetDefinitionsAsync(projectId).Result; var buildDefinitions = definitions.Where(d => d.Name == _options.BuildQueueName && d.DefinitionQuality != DefinitionQuality.Draft).ToList(); if (buildDefinitions.Count != 1) { throw new Exception($"Expected one build definition named {_options.BuildQueueName} but found {buildDefinitions.Count}."); } var buildDefinitionIds = new int[] { buildDefinitions.Single().Id }; var builds = buildClient.GetBuildsAsync(projectId, buildDefinitionIds, statusFilter: BuildStatus.Completed).Result; var modifiedBuilds = new HashSet <Build>(); Console.WriteLine(); Console.WriteLine("Determining which builds should be marked for retention..."); foreach (var build in builds) { var insertedBuild = uniqueInsertedBuilds.FirstOrDefault(b => NormalizeBranchName(b.InsertedBuildBranch) == NormalizeBranchName(build.SourceBranch) && b.InsertedBuildNumber == build.BuildNumber); if (insertedBuild != null && insertedBuild.ReleaseTags.Any() && !build.Tags.Contains(ReleasedToPublicTag)) { buildClient.AddBuildTagAsync(projectId, build.Id, ReleasedToPublicTag).Wait(); } if (insertedBuild != null || build.Tags.Contains(ReleasedToPublicTag)) { if (!build.KeepForever.GetValueOrDefault()) { Console.WriteLine($"Adding '{NormalizeBranchName(build.SourceBranch)} - {build.BuildNumber}' to the list of builds to keep forever."); build.KeepForever = true; modifiedBuilds.Add(build); } } else if (build.KeepForever.GetValueOrDefault()) { // no longer needed Console.WriteLine($"Removing '{NormalizeBranchName(build.SourceBranch)} - {build.BuildNumber}' from the list of builds to keep forever."); build.KeepForever = false; modifiedBuilds.Add(build); } } Console.WriteLine($" Found {modifiedBuilds.Count} builds which need their retention setting modified."); Console.WriteLine(); if (modifiedBuilds.Count > 0) { buildClient.UpdateBuildsAsync(modifiedBuilds, projectId).Wait(); } } stopwatch.Stop(); Console.WriteLine(); Console.WriteLine($"Total Time: {stopwatch.Elapsed.TotalSeconds} seconds"); } }
private bool TryUpdateTag(GitHttpClient gitHttpClient, Guid vsRepoGuid, TagData tag, GitVersionDescriptor versionDescriptor, string componentsJsonFile) { Stream itemContentStream; try { itemContentStream = gitHttpClient.GetItemContentAsync(Settings.Default.TFSProjectName, vsRepoGuid, componentsJsonFile, versionDescriptor: versionDescriptor).Result; } catch (AggregateException e) when(e.InnerException.Message.Contains("TF401174")) // item could not be found { // That file doesn't exist in this drop; return(false); } using (itemContentStream) using (var jsonReader = new JsonTextReader(new StreamReader(itemContentStream))) { var jsonDocument = (JObject)(JToken.ReadFrom(jsonReader)); var components = jsonDocument["Components"]; var component = components[_options.ComponentName]; if (component == null) { return(false); } var componentUrl = component["url"].Value <string>(); var componentParts = componentUrl.Split(';').First().Split('/'); tag.InsertedBuildBranch = componentParts[componentParts.Length - 2]; tag.InsertedBuildNumber = componentParts[componentParts.Length - 1]; // Just to protect against us getting something bad, assert the build number is numeric if (!Regex.IsMatch(tag.InsertedBuildNumber, "^[0-9.]+$")) { throw new Exception($"{tag.InsertedBuildNumber} doesn't look numeric."); } } return(true); }
public static async Task <(bool success, int pullRequestId)> PerformInsertionAsync( RoslynInsertionToolOptions options, CancellationToken cancellationToken) { Options = options; Console.WriteLine($"{Environment.NewLine}New Insertion Into {Options.VisualStudioBranchName} Started{Environment.NewLine}"); var newPackageFiles = new List <string>(); try { Console.WriteLine($"Verifying given authentication for {Options.VSTSUri}"); try { ProjectCollection.Authenticate(); } catch (Exception ex) { LogError($"Could not authenticate with {Options.VSTSUri}"); LogError(ex); return(false, 0); } Console.WriteLine($"Verification succeeded for {Options.VSTSUri}"); // ********************** Create dummy PR ***************************** if (Options.CreateDummyPr) { GitPullRequest dummyPR; try { dummyPR = await CreatePlaceholderBranchAsync(cancellationToken); } catch (Exception ex) { LogError($"Unable to create placeholder PR for '{options.VisualStudioBranchName}'"); LogError(ex); return(false, 0); } if (dummyPR == null) { LogError($"Unable to create placeholder PR for '{options.VisualStudioBranchName}'"); return(false, 0); } return(true, dummyPR.PullRequestId); } // ********************** Get Last Insertion ***************************** cancellationToken.ThrowIfCancellationRequested(); BuildVersion buildVersion; Build buildToInsert; Build latestBuild = null; bool retainBuild = false; // Get the version from DevOps Pipelines queue, e.g. Roslyn-Master-Signed-Release. if (string.IsNullOrEmpty(Options.SpecificBuild)) { buildToInsert = await GetLatestPassedBuildAsync(cancellationToken); buildVersion = BuildVersion.FromTfsBuildNumber(buildToInsert.BuildNumber, Options.BuildQueueName); Console.WriteLine("Found build number " + buildVersion); // Get the latest build, whether passed or failed. If the buildToInsert has already been inserted but // there is a later failing build, then send an error latestBuild = await GetLatestBuildAsync(cancellationToken); } else { buildVersion = BuildVersion.FromString(Options.SpecificBuild); buildToInsert = await GetSpecificBuildAsync(buildVersion, cancellationToken); } var insertionArtifacts = await GetInsertionArtifactsAsync(buildToInsert, cancellationToken); cancellationToken.ThrowIfCancellationRequested(); // *********** Look up existing PR ******************** var gitClient = ProjectCollection.GetClient <GitHttpClient>(); var branches = await gitClient.GetRefsAsync( VSRepoId, filter : $"heads/{Options.VisualStudioBranchName}", cancellationToken : cancellationToken); var baseBranch = branches.Single(b => b.Name == $"refs/heads/{Options.VisualStudioBranchName}"); var pullRequestId = Options.UpdateExistingPr; var useExistingPr = pullRequestId != 0; GitPullRequest pullRequest; string insertionBranchName; if (useExistingPr) { pullRequest = await gitClient.GetPullRequestByIdAsync(pullRequestId, cancellationToken : cancellationToken); insertionBranchName = pullRequest.SourceRefName.Substring("refs/heads/".Length); var refs = await gitClient.GetRefsAsync(VSRepoId, filter : $"heads/{insertionBranchName}", cancellationToken : cancellationToken); var insertionBranch = refs.Single(r => r.Name == $"refs/heads/{insertionBranchName}"); if (Options.OverwritePr) { // overwrite existing PR branch back to base before pushing new commit var updateToBase = new GitRefUpdate { OldObjectId = insertionBranch.ObjectId, NewObjectId = baseBranch.ObjectId, Name = $"refs/heads/{insertionBranchName}" }; await gitClient.UpdateRefsAsync(new[] { updateToBase }, VSRepoId, cancellationToken : cancellationToken); } else { // not overwriting PR, so the insertion branch is actually the base baseBranch = insertionBranch; } } else { pullRequest = null; insertionBranchName = GetNewBranchName(); } var allChanges = new List <GitChange>(); var coreXT = await CoreXT.Load(gitClient, baseBranch.ObjectId); if (Options.InsertCoreXTPackages) { // ************** Update Nuget Packages For Branch************************ cancellationToken.ThrowIfCancellationRequested(); Console.WriteLine($"Updating Nuget Packages"); bool success; (success, newPackageFiles) = UpdatePackages( buildVersion, coreXT, insertionArtifacts.GetPackagesDirectory(), cancellationToken); retainBuild |= success; // *********** Copy OptimizationInputs.props file *********************** foreach (var propsFile in insertionArtifacts.GetOptProfPropertyFiles()) { var targetFilePath = "src/Tests/config/runsettings/Official/OptProf/External/" + Path.GetFileName(propsFile); var version = new GitVersionDescriptor { VersionType = GitVersionType.Commit, Version = baseBranch.ObjectId }; var stream = await gitClient.GetItemContentAsync(VSRepoId, targetFilePath, download : true, versionDescriptor : version); var originalContent = new StreamReader(stream).ReadToEnd(); var newContent = File.ReadAllText(propsFile); if (GetChangeOpt(targetFilePath, originalContent, newContent) is GitChange change) { allChanges.Add(change); } } } if (Options.UpdateCoreXTLibraries || Options.UpdateAssemblyVersions) { // ************** Update assembly versions ************************ cancellationToken.ThrowIfCancellationRequested(); Console.WriteLine($"Updating assembly versions"); if (await UpdateAssemblyVersionsOpt(gitClient, baseBranch.ObjectId, insertionArtifacts) is GitChange assemblyVersionChange) { allChanges.Add(assemblyVersionChange); } // if we got this far then we definitely need to retain this build retainBuild = true; } // *********** Update toolset ******************** if (Options.InsertToolset) { UpdateToolsetPackage(coreXT, insertionArtifacts, buildVersion); retainBuild = true; } // ************ Update .corext\Configs\default.config ******************** cancellationToken.ThrowIfCancellationRequested(); Console.WriteLine($"Updating CoreXT default.config file"); if (coreXT.SaveConfigOpt() is GitChange configChange) { allChanges.Add(configChange); } // *********** Update .corext\Configs\components.json ******************** BuildVersion oldComponentVersion = default; if (Options.InsertWillowPackages) { cancellationToken.ThrowIfCancellationRequested(); Console.WriteLine($"Updating CoreXT components file"); var components = await GetLatestComponentsAsync(buildToInsert, cancellationToken); var shouldSave = false; foreach (var newComponent in components) { if (coreXT.TryGetComponentByName(newComponent.Name, out var oldComponent)) { if (oldComponent.BuildVersion != default) { oldComponentVersion = oldComponent.BuildVersion; } coreXT.UpdateComponent(newComponent); shouldSave = true; } } if (shouldSave) { var allComponentChanges = coreXT.SaveComponents(); allChanges.AddRange(allComponentChanges); retainBuild = true; } } // ************* Ensure the build is retained on the servers ************* if (Options.RetainInsertedBuild && retainBuild && !buildToInsert.KeepForever.GetValueOrDefault()) { Console.WriteLine("Marking inserted build for retention."); buildToInsert.KeepForever = true; var buildClient = ProjectCollection.GetClient <BuildHttpClient>(); await buildClient.UpdateBuildAsync(buildToInsert); } // ************* Bail out if there are no changes ************************ if (!allChanges.Any()) { LogWarning("No meaningful changes since the last insertion was merged. PR will not be created or updated."); return(true, 0); } // ********************* Create push ************************************* var insertionBranchUpdate = new GitRefUpdate { Name = $"refs/heads/{insertionBranchName}", OldObjectId = baseBranch.ObjectId }; var commit = new GitCommitRef { Comment = $"Updating {Options.InsertionName} to {buildVersion}", Changes = allChanges }; var push = new GitPush { RefUpdates = new[] { insertionBranchUpdate }, Commits = new[] { commit } }; await gitClient.CreatePushAsync(push, VSRepoId, cancellationToken : cancellationToken); // ********************* Create pull request ***************************** var oldBuild = await GetSpecificBuildAsync(oldComponentVersion, cancellationToken); var prDescriptionMarkdown = CreatePullRequestDescription(oldBuild, buildToInsert, useMarkdown: true); if (buildToInsert.Result == BuildResult.PartiallySucceeded) { prDescriptionMarkdown += Environment.NewLine + ":warning: The build being inserted has partially succeeded."; } if (!useExistingPr || Options.OverwritePr) { try { var nl = Environment.NewLine; if (oldBuild is null) { prDescriptionMarkdown += $"{nl}---{nl}Unable to find details for previous build ({oldComponentVersion}){nl}"; } else { var(changes, diffLink) = await GetChangesBetweenBuildsAsync(oldBuild, buildToInsert, cancellationToken); var diffDescription = changes.Any() ? $"[View Complete Diff of Changes]({diffLink})" : "No source changes since previous insertion"; prDescriptionMarkdown += nl + "---" + nl + diffDescription + nl; prDescriptionMarkdown = AppendChangesToDescription(prDescriptionMarkdown, oldBuild ?? buildToInsert, changes); } } catch (Exception e) { LogWarning("Failed to create diff links."); LogWarning(e.Message); } } if (useExistingPr) { try { if (Options.OverwritePr) { pullRequest = await OverwritePullRequestAsync(pullRequestId, prDescriptionMarkdown, buildVersion.ToString(), options.TitlePrefix, cancellationToken); } pullRequestId = pullRequest.PullRequestId; } catch (Exception ex) { LogError($"Unable to update pull request for '{pullRequest.SourceRefName}'"); LogError(ex); return(false, 0); } } else { // create a new PR Console.WriteLine($"Create Pull Request"); try { // If this insertion was queued for PR validation, for a dev branch, or for a feature branch, // then add the build queuer as a reviewer instead of mlinfraswat. var isPrValidation = !string.IsNullOrEmpty(GetBuildPRNumber(buildToInsert)); var isDevOrFeatureBranch = Options.BranchName.StartsWith("dev/") || Options.BranchName.StartsWith("features/"); var reviewerId = isPrValidation || isDevOrFeatureBranch ? buildToInsert.RequestedBy.Id : MLInfraSwatUserId.ToString(); pullRequest = await CreatePullRequestAsync(insertionBranchName, prDescriptionMarkdown, buildVersion.ToString(), options.TitlePrefix, reviewerId, cancellationToken); if (pullRequest == null) { LogError($"Unable to create pull request for '{insertionBranchName}'"); return(false, 0); } pullRequestId = pullRequest.PullRequestId; } catch (Exception ex) { LogError($"Unable to create pull request for '{insertionBranchName}'"); LogError(ex); return(false, 0); } } // ********************* Create validation build ***************************** if (Options.QueueValidationBuild) { cancellationToken.ThrowIfCancellationRequested(); Console.WriteLine($"Create Validation Build"); try { if (Options.CreateDraftPr) { // When creating Draft PRs no policies are automatically started. // If we do not queue a CloudBuild the Perf DDRITs request will // spin waiting for a build to test against until it timesout. await QueueBuildPolicy(pullRequest, "CloudBuild - PR"); } await QueueBuildPolicy(pullRequest, "Request Perf DDRITs"); } catch (Exception ex) { LogWarning($"Unable to create a CloudBuild validation build for '{insertionBranchName}'"); LogWarning(ex); } if (Options.CreateDraftPr) { // When creating Draft PRs no policies are automatically started. await TryQueueBuildPolicy(pullRequest, "Insertion Hash Check", insertionBranchName); await TryQueueBuildPolicy(pullRequest, "Insertion Sign Check", insertionBranchName); await TryQueueBuildPolicy(pullRequest, "Insertion Symbol Check", insertionBranchName); } } // ********************* Set PR to Auto-Complete ***************************** if (Options.SetAutoComplete) { cancellationToken.ThrowIfCancellationRequested(); Console.WriteLine($"Set PR to Auto-Complete"); try { var prDescriptionText = CreatePullRequestDescription(oldBuild, buildToInsert, useMarkdown: false); await SetAutoCompleteAsync(pullRequest, prDescriptionText, cancellationToken); } catch (Exception ex) { LogWarning($"Unable to Set PR to Auto-Complete for '{insertionBranchName}'"); LogWarning(ex); } } return(true, pullRequestId); } catch (Exception ex) { LogError(ex); return(false, 0); } finally { Options = null; } }
private async Task <List <GitChange> > GetChanges(Guid repoId, IPackageHandler handler, string packageVersion, GitVersionDescriptor versionRef, IEnumerable <GitItem> items) { var changes = new List <GitChange>(); foreach (var item in items) { var shouldUpdate = await handler.ShouldUpdate(item.Path).ConfigureAwait(false); if (shouldUpdate) { var itemRef = await _gitClient.GetItemContentAsync(repoId, item.Path, includeContent : true, versionDescriptor : versionRef).ConfigureAwait(false); var oldContent = await itemRef.GetContent().ConfigureAwait(false); var newContent = await handler.Update(oldContent, packageVersion).ConfigureAwait(false); if (!string.Equals(oldContent, newContent)) { changes.Add(CreateChange(item.Path, newContent)); Log($"Item content of {item.Path} received and changed."); } } } return(changes); }
private static GitQueryCommitsCriteria GetBaseCommits(GitVersionDescriptor itemVersion) => new GitQueryCommitsCriteria { ItemVersion = itemVersion, };
public static async Task <(bool success, int pullRequestId)> PerformInsertionAsync( RoslynInsertionToolOptions options, CancellationToken cancellationToken) { Options = options; Console.WriteLine($"{Environment.NewLine}New Insertion Into {Options.VisualStudioBranchName} Started{Environment.NewLine}"); var newPackageFiles = new List <string>(); try { Console.WriteLine($"Verifying given authentication for {Options.VisualStudioRepoAzdoUri}"); try { VisualStudioRepoConnection.Authenticate(); } catch (Exception ex) { LogError($"Could not authenticate with {Options.VisualStudioRepoAzdoUri}"); LogError(ex); return(false, 0); } Console.WriteLine($"Verification succeeded for {Options.VisualStudioRepoAzdoUri}"); if (ComponentBuildConnection != VisualStudioRepoConnection) { Console.WriteLine($"Verifying given authentication for {Options.ComponentBuildAzdoUri}"); try { ComponentBuildConnection.Authenticate(); } catch (Exception ex) { LogError($"Could not authenticate with {Options.ComponentBuildAzdoUri}"); LogError(ex); return(false, 0); } Console.WriteLine($"Verification succeeded for {Options.ComponentBuildAzdoUri}"); } // ********************** Create dummy PR ***************************** if (Options.CreateDummyPr) { GitPullRequest dummyPR; try { dummyPR = await CreatePlaceholderVSBranchAsync(cancellationToken); } catch (Exception ex) { LogError($"Unable to create placeholder PR for '{options.VisualStudioBranchName}'"); LogError(ex); return(false, 0); } if (dummyPR == null) { LogError($"Unable to create placeholder PR for '{options.VisualStudioBranchName}'"); return(false, 0); } return(true, dummyPR.PullRequestId); } // ********************** Get Last Insertion ***************************** cancellationToken.ThrowIfCancellationRequested(); BuildVersion buildVersion; Build buildToInsert; Build latestBuild = null; bool retainBuild = false; // Get the version from DevOps Pipelines queue, e.g. Roslyn-Main-Signed-Release. if (string.IsNullOrEmpty(Options.SpecificBuild)) { buildToInsert = await GetLatestPassedComponentBuildAsync(cancellationToken); buildVersion = BuildVersion.FromTfsBuildNumber(buildToInsert.BuildNumber, Options.ComponentBuildQueueName); Console.WriteLine("Found " + buildToInsert.Definition.Name + " build number " + buildVersion); // Get the latest build, whether passed or failed. If the buildToInsert has already been inserted but // there is a later failing build, then send an error latestBuild = await GetLatestComponentBuildAsync(cancellationToken); } else { buildVersion = BuildVersion.FromString(Options.SpecificBuild); buildToInsert = await GetSpecificComponentBuildAsync(buildVersion, cancellationToken); } var insertionArtifacts = await GetInsertionArtifactsAsync(buildToInsert, cancellationToken); cancellationToken.ThrowIfCancellationRequested(); // *********** Look up existing PR ******************** var gitClient = VisualStudioRepoConnection.GetClient <GitHttpClient>(); var branches = await gitClient.GetRefsAsync( VSRepoId, filter : $"heads/{Options.VisualStudioBranchName}", cancellationToken : cancellationToken); var baseBranch = branches.Single(b => b.Name == $"refs/heads/{Options.VisualStudioBranchName}"); var pullRequestId = Options.UpdateExistingPr; var useExistingPr = pullRequestId != 0; GitPullRequest pullRequest; string insertionBranchName; if (useExistingPr) { pullRequest = await gitClient.GetPullRequestByIdAsync(pullRequestId, cancellationToken : cancellationToken); insertionBranchName = pullRequest.SourceRefName.Substring("refs/heads/".Length); var refs = await gitClient.GetRefsAsync(VSRepoId, filter : $"heads/{insertionBranchName}", cancellationToken : cancellationToken); var insertionBranch = refs.Single(r => r.Name == $"refs/heads/{insertionBranchName}"); if (Options.OverwritePr) { // overwrite existing PR branch back to base before pushing new commit var updateToBase = new GitRefUpdate { OldObjectId = insertionBranch.ObjectId, NewObjectId = baseBranch.ObjectId, Name = $"refs/heads/{insertionBranchName}" }; var results = await gitClient.UpdateRefsAsync(new[] { updateToBase }, VSRepoId, cancellationToken : cancellationToken); foreach (var result in results) { if (!result.Success) { LogError("Failed to overwrite PR: " + result.CustomMessage); } } } else { // not overwriting PR, so the insertion branch is actually the base baseBranch = insertionBranch; } } else { pullRequest = null; insertionBranchName = GetNewBranchName(); } var allChanges = new List <GitChange>(); var coreXT = await CoreXT.Load(gitClient, baseBranch.ObjectId); if (Options.InsertCoreXTPackages) { // ************** Update Nuget Packages For Branch************************ cancellationToken.ThrowIfCancellationRequested(); Console.WriteLine($"Updating Nuget Packages"); bool success; (success, newPackageFiles) = UpdatePackages( buildVersion, coreXT, insertionArtifacts.GetPackagesDirectory(), Options.SkipCoreXTPackages, cancellationToken); retainBuild |= success; // *********** Copy OptimizationInputs.props file *********************** foreach (var propsFile in insertionArtifacts.GetOptProfPropertyFiles()) { var propsFilename = Path.GetFileName(propsFile); if (propsFilename == "dotnet-roslyn.props") { // Since the propsFilename is based on repo name, during Roslyn's transition from inserting // from GH dotnet/roslyn builds to inserting from dnceng dotnet-roslyn builds, this will // ensure that we look for the proper props filename. propsFilename = "dotnet.roslyn.props"; } var targetFilePath = $"src/Tests/config/runsettings/Official/OptProf/External/{propsFilename}"; var version = new GitVersionDescriptor { VersionType = GitVersionType.Commit, Version = baseBranch.ObjectId }; var stream = await gitClient.GetItemContentAsync(VSRepoId, targetFilePath, download : true, versionDescriptor : version); var originalContent = new StreamReader(stream).ReadToEnd(); var newContent = File.ReadAllText(propsFile); if (GetChangeOpt(targetFilePath, originalContent, newContent) is GitChange change) { allChanges.Add(change); } } } if (Options.UpdateCoreXTLibraries || Options.UpdateAssemblyVersions) { // ************** Update assembly versions ************************ cancellationToken.ThrowIfCancellationRequested(); Console.WriteLine($"Updating assembly versions"); if (await UpdateAssemblyVersionsOpt(gitClient, baseBranch.ObjectId, insertionArtifacts) is GitChange assemblyVersionChange) { allChanges.Add(assemblyVersionChange); } // if we got this far then we definitely need to retain this build retainBuild = true; } // *********** Update toolset ******************** if (Options.InsertToolset) { UpdateToolsetPackage(coreXT, insertionArtifacts, buildVersion); retainBuild = true; } // ************ Update .corext\Configs\default.config ******************** cancellationToken.ThrowIfCancellationRequested(); Console.WriteLine($"Updating CoreXT default.config and props files under src/ConfigData/Packages"); foreach (var configChange in coreXT.SaveConfigs()) { if (configChange is not null) { allChanges.Add(configChange); } } // *********** Update .corext\Configs\components.json ******************** BuildVersion oldComponentVersion = default; if (Options.InsertWillowPackages) { cancellationToken.ThrowIfCancellationRequested(); Console.WriteLine($"Updating CoreXT components file"); var components = GetLatestBuildComponents(buildToInsert, insertionArtifacts, cancellationToken); var shouldSave = false; foreach (var newComponent in components) { if (coreXT.TryGetComponentByName(newComponent.Name, out var oldComponent)) { if (oldComponent.BuildVersion != default) { oldComponentVersion = oldComponent.BuildVersion; } coreXT.UpdateComponent(newComponent); shouldSave = true; } } if (shouldSave) { var allComponentChanges = coreXT.SaveComponents(); allChanges.AddRange(allComponentChanges); retainBuild = true; } } // ************* Ensure the build is retained on the servers ************* if (Options.RetainInsertedBuild && retainBuild && !buildToInsert.KeepForever.GetValueOrDefault()) { await RetainComponentBuild(buildToInsert); } // ************* Bail out if there are no changes ************************ if (!allChanges.Any() && options.CherryPick.IsDefaultOrEmpty) { LogWarning("No meaningful changes since the last insertion was merged. PR will not be created or updated."); return(true, 0); } // ********************* Create push ************************************* var currentCommit = baseBranch.ObjectId; if (allChanges.Any()) { var insertionBranchUpdate = new GitRefUpdate { Name = $"refs/heads/{insertionBranchName}", OldObjectId = baseBranch.ObjectId }; var commit = new GitCommitRef { Comment = $"Updating {Options.InsertionName} to {buildVersion}", Changes = allChanges }; var push = new GitPush { RefUpdates = new[] { insertionBranchUpdate }, Commits = new[] { commit } }; push = await gitClient.CreatePushAsync(push, VSRepoId, cancellationToken : cancellationToken); currentCommit = push.Commits.Single().CommitId; } // ********************* Cherry-pick VS commits ***************************** var cherryPickCommits = Options.CherryPick; if (!cherryPickCommits.IsDefaultOrEmpty) { Console.WriteLine("Cherry-picking the following VS commits:"); foreach (var cherryPickCommit in cherryPickCommits) { var gc = await gitClient.GetCommitAsync(cherryPickCommit, VSRepoId, cancellationToken : cancellationToken); Console.WriteLine("- " + gc.RemoteUrl); } var commitRefs = cherryPickCommits.Select(id => new GitCommitRef() { CommitId = id }).ToArray(); var cherryPickBranchName = $"{insertionBranchName}-cherry-pick-{DateTime.Now:yyyyMMddHHmmss}"; var cherryPickArgs = new GitAsyncRefOperationParameters() { Source = new GitAsyncRefOperationSource() { CommitList = commitRefs }, OntoRefName = $"refs/heads/{insertionBranchName}", GeneratedRefName = $"refs/heads/{cherryPickBranchName}" }; // Cherry-pick VS commits into insertion branch. var cherryPick = await gitClient.CreateCherryPickAsync(cherryPickArgs, Options.VisualStudioRepoProjectName, VSRepoId, cancellationToken : cancellationToken); while (cherryPick.Status < GitAsyncOperationStatus.Completed) { Console.WriteLine($"Cherry-pick progress: {cherryPick.DetailedStatus?.Progress ?? 0:P}"); await Task.Delay(5000); cherryPick = await gitClient.GetCherryPickAsync(options.VisualStudioRepoProjectName, cherryPick.CherryPickId, VSRepoId, cancellationToken : cancellationToken); } Console.WriteLine($"Cherry-pick status: {cherryPick.Status}"); if (cherryPick.Status == GitAsyncOperationStatus.Completed) { var cherryPickBranch = await gitClient.GetBranchAsync(VSRepoId, cherryPickBranchName, cancellationToken : cancellationToken); var addCherryPickedCommits = new GitRefUpdate { OldObjectId = currentCommit, NewObjectId = cherryPickBranch.Commit.CommitId, Name = $"refs/heads/{insertionBranchName}" }; var results = await gitClient.UpdateRefsAsync(new[] { addCherryPickedCommits }, VSRepoId, cancellationToken : cancellationToken); foreach (var result in results) { if (!result.Success) { LogError("Failed to reset ref to cherry-pick branch: " + result.CustomMessage); } } } else { LogError("Cherry-picking failed: " + cherryPick.DetailedStatus.FailureMessage); } } // ********************* Create pull request ***************************** var oldBuild = await GetSpecificComponentBuildAsync(oldComponentVersion, cancellationToken); var prDescriptionMarkdown = CreatePullRequestDescription(oldBuild, buildToInsert, useMarkdown: true); if (buildToInsert.Result == BuildResult.PartiallySucceeded) { prDescriptionMarkdown += Environment.NewLine + ":warning: The build being inserted has partially succeeded."; } if (!useExistingPr || Options.OverwritePr) { try { var nl = Environment.NewLine; if (oldBuild is null) { prDescriptionMarkdown += $"{nl}---{nl}Unable to find details for previous build ({oldComponentVersion}){nl}"; } else { var(changes, diffLink) = await GetChangesBetweenBuildsAsync(oldBuild, buildToInsert, cancellationToken); var diffDescription = changes.Any() ? $"[View Complete Diff of Changes]({diffLink})" : "No source changes since previous insertion"; prDescriptionMarkdown += nl + "---" + nl + diffDescription + nl; prDescriptionMarkdown = AppendChangesToDescription(prDescriptionMarkdown, oldBuild ?? buildToInsert, changes); } } catch (Exception e) { LogWarning("Failed to create diff links."); LogWarning(e.Message); } } if (useExistingPr) { try { if (Options.OverwritePr) { pullRequest = await OverwritePullRequestAsync(pullRequestId, prDescriptionMarkdown, buildVersion.ToString(), cancellationToken); } pullRequestId = pullRequest.PullRequestId; } catch (Exception ex) { LogError($"Unable to update pull request for '{pullRequest.SourceRefName}'"); LogError(ex); return(false, 0); } } else { // create a new PR Console.WriteLine($"Create Pull Request"); try { // If this insertion was queued for PR validation, for a dev branch, for a feature branch, // or if no default reviewer is specified, then add the build queuer as a reviewer. var isPrValidation = !string.IsNullOrEmpty(GetBuildPRNumber(buildToInsert)); var isDevOrFeatureBranch = Options.ComponentBranchName.StartsWith("dev/") || Options.ComponentBranchName.StartsWith("features/"); bool hasReviewer = !string.IsNullOrEmpty(Options.ReviewerGUID); // Easiest way to get the reviewer GUIDs is to create a PR search in AzDo // You'll get something like https://dev.azure.com/devdiv/DevDiv/_git/VS/pullrequests?_a=active&createdBy=GUID-here var reviewerId = (isPrValidation || isDevOrFeatureBranch) || !hasReviewer ? buildToInsert.RequestedBy.Id : Options.ReviewerGUID; pullRequest = await CreateVSPullRequestAsync(insertionBranchName, prDescriptionMarkdown, buildVersion.ToString(), reviewerId, cancellationToken); if (pullRequest == null) { LogError($"Unable to create pull request for '{insertionBranchName}'"); return(false, 0); } pullRequestId = pullRequest.PullRequestId; } catch (Exception ex) { LogError($"Unable to create pull request for '{insertionBranchName}'"); LogError(ex); return(false, 0); } } // ********************* Create validation build ***************************** if (Options.QueueValidationBuild) { cancellationToken.ThrowIfCancellationRequested(); Console.WriteLine($"Create Validation Build"); try { if (Options.CreateDraftPr) { // When creating Draft PRs no policies are automatically started. // If we do not queue a CloudBuild the Perf DDRITs request will // spin waiting for a build to test against until it timesout. await QueueVSBuildPolicy(pullRequest, "CloudBuild - PR"); } await QueueVSBuildPolicy(pullRequest, "Request Perf DDRITs"); } catch (Exception ex) { LogWarning($"Unable to create a CloudBuild validation build for '{insertionBranchName}'"); LogWarning(ex); } if (Options.CreateDraftPr) { // When creating Draft PRs no policies are automatically started. await TryQueueVSBuildPolicy(pullRequest, "Insertion Hash Check", insertionBranchName); await TryQueueVSBuildPolicy(pullRequest, "Insertion Sign Check", insertionBranchName); await TryQueueVSBuildPolicy(pullRequest, "Insertion Symbol Check", insertionBranchName); } } // ********************* Set PR to Auto-Complete ***************************** if (Options.SetAutoComplete) { cancellationToken.ThrowIfCancellationRequested(); Console.WriteLine($"Set PR to Auto-Complete"); try { var prDescriptionText = CreatePullRequestDescription(oldBuild, buildToInsert, useMarkdown: false); await SetAutoCompleteAsync(pullRequest, prDescriptionText, cancellationToken); } catch (Exception ex) { LogWarning($"Unable to Set PR to Auto-Complete for '{insertionBranchName}'"); LogWarning(ex); } } return(true, pullRequestId); } catch (Exception ex) { LogError(ex); return(false, 0); } finally { Options = null; } }