private string GetUpdateBlockedReason( GitHubPullRequest pr, GitCommit headCommit, string upgradeBranchPrefix, GitHubProject origin) { if (pr.Head.User.Login != origin.Owner) { return($"Owner of head repo '{pr.Head.User.Login}' is not '{origin.Owner}'"); } if (!pr.Head.Ref.StartsWith(upgradeBranchPrefix)) { return($"Ref name '{pr.Head.Ref}' does not start with '{upgradeBranchPrefix}'"); } if (headCommit.Author.Name != GitAuthorName) { return($"Head commit author '{headCommit.Author.Name}' is not '{GitAuthorName}'"); } if (headCommit.Committer.Name != GitAuthorName) { return($"Head commit committer '{headCommit.Committer.Name}' is not '{GitAuthorName}'"); } if (pr.Labels?.Any(IsMaestroStopUpdatesLabel) ?? false) { return($"Label `{MaestroStopUpdatesLabel}` is attached"); } return(null); }
public GitHubVersionsRepoUpdater(GitHubAuth gitHubAuth, GitHubProject project, INupkgInfoFactory nupkgInfoFactory) : base(nupkgInfoFactory) { if (gitHubAuth == null) { throw new ArgumentNullException(nameof(gitHubAuth)); } _gitHubAuth = gitHubAuth; if (project == null) { throw new ArgumentNullException(nameof(project)); } _project = project; }
public GitHubBranch(string name, GitHubProject project) { if (name == null) { throw new ArgumentNullException(nameof(name)); } Name = name; if (project == null) { throw new ArgumentNullException(nameof(project)); } Project = project; }
public GitHubVersionsRepoUpdater(GitHubAuth gitHubAuth, GitHubProject project) { if (gitHubAuth == null) { throw new ArgumentNullException(nameof(gitHubAuth)); } _gitHubAuth = gitHubAuth; if (project == null) { throw new ArgumentNullException(nameof(project)); } _project = project; }
public VersionsRepoUpdater(GitHubAuth gitHubAuth, GitHubProject project) { if (gitHubAuth == null) { throw new ArgumentNullException(nameof(gitHubAuth)); } _gitHubAuth = gitHubAuth; if (project == null) { throw new ArgumentNullException(nameof(project)); } _project = project; }
public PullRequestCreator( GitHubAuth auth, GitHubProject origin, GitHubBranch upstreamBranch, string gitAuthorName = null, IUpdateBranchNamingStrategy namingStrategy = null) { _auth = auth; Origin = origin; UpstreamBranch = upstreamBranch; GitAuthorName = gitAuthorName ?? auth.User; _namingStrategy = namingStrategy ?? new SingleBranchNamingStrategy("UpdateDependencies"); }
private async Task PostDiscardedCommitCommentAsync( GitHubProject baseProject, GitHubPullRequest pullRequestToUpdate, GitCommit oldCommit, GitHubClient client) { GitHubCombinedStatus combinedStatus = await client.GetStatusAsync( baseProject, oldCommit.Sha); CiStatusLine[] statuses = combinedStatus .Statuses .OrderBy(s => s.State) .ThenBy(s => s.Context) .Select(CiStatusLine.Create) .ToArray(); string statusLines = statuses .Aggregate(string.Empty, (acc, line) => acc + line.MarkdownLine + "\r\n"); string ciSummary = string.Join( " ", statuses .GroupBy(s => s.Emoticon) .Select(g => $"{g.Count()}{g.Key}") .ToArray()); string commentBody = $"Discarded [`{oldCommit.Sha.Substring(0, 7)}`]({oldCommit.HtmlUrl}): " + $"`{oldCommit.Message}`"; if (statuses.Any()) { commentBody += "\r\n\r\n" + "<details>" + "<summary>" + $"CI Status: {ciSummary} (click to expand)\r\n" + "</summary>" + $"\r\n\r\n{statusLines}\r\n" + "</details>"; } await client.PostCommentAsync( baseProject, pullRequestToUpdate.Number, commentBody); }
public override bool Execute() { MsBuildTraceListener[] listeners = Trace.Listeners.AddMsBuildTraceListeners(Log); try { IDependencyUpdater[] updaters = GetDependencyUpdaters().ToArray(); BuildInfo[] buildInfos = GetBuildInfos().ToArray(); var updater = new DependencyUpdater(); DependencyUpdateResults updateResults = updater.Update(updaters, buildInfos); if (updateResults.ChangesDetected()) { var gitHubAuth = new GitHubAuth(GitHubAuthToken, GitHubUser, GitHubEmail); var origin = new GitHubProject(ProjectRepoName, GitHubUser); var upstreamBranch = new GitHubBranch( ProjectRepoBranch, new GitHubProject(ProjectRepoName, ProjectRepoOwner)); string suggestedMessage = updateResults.GetSuggestedCommitMessage(); string body = string.Empty; if (NotifyGitHubUsers != null) { body += PullRequestCreator.NotificationString(NotifyGitHubUsers.Select(item => item.ItemSpec)); } var prCreator = new PullRequestCreator(gitHubAuth, origin, upstreamBranch, GitHubAuthor); prCreator.CreateOrUpdateAsync( suggestedMessage, suggestedMessage + $" ({ProjectRepoBranch})", body, forceCreate: AlwaysCreateNewPullRequest).Wait(); } } finally { Trace.Listeners.RemoveMsBuildTraceListeners(listeners); } return true; }
private async Task <string> CreateDiscardedCommitListBodyAsync( GitHubProject baseProject, GitHubPullRequest pullRequestToUpdate, GitCommit oldCommit, GitHubClient client) { // GitHub returns the HTML "commit" url, but we want "commits" so that CI results show. string oldCommitsUrl = oldCommit.HtmlUrl.Replace("commit", "commits"); GitHubCombinedStatus combinedStatus = await client.GetStatusAsync( baseProject, oldCommit.Sha); string statusLines = combinedStatus .Statuses .OrderBy(s => s.State) .ThenBy(s => s.Context) .Select(GetStatusLine) .Aggregate(string.Empty, (acc, line) => acc + line + "\r\n"); string oldCommitEntry = $" * [`{oldCommit.Sha.Substring(0, 7)}`]({oldCommitsUrl}) {oldCommit.Message}\r\n" + $"{statusLines}"; // Find insertion point. GitHub always returns \r\n. string insertionMarker = $"<{DiscardedCommitElementName}>\r\n\r\n"; string endInsertionMarker = $"\r\n</{DiscardedCommitElementName}>"; int elementBegin = pullRequestToUpdate.Body.IndexOf( insertionMarker, StringComparison.Ordinal); if (elementBegin != -1) { return(pullRequestToUpdate.Body.Insert( elementBegin + insertionMarker.Length, oldCommitEntry)); } return(pullRequestToUpdate.Body + "<details><summary>Discarded auto-update commits (click to expand)</summary>" + $"{insertionMarker}{oldCommitEntry}{endInsertionMarker}" + "</details>"); }
public async Task CreateOrUpdateAsync( string commitMessage, string title, string description, GitHubBranch baseBranch, GitHubProject origin, PullRequestOptions options) { using (var client = new GitHubClient(_auth)) { await CreateOrUpdateAsync( commitMessage, title, description, baseBranch, origin, options, client); } }
private string GetUpdateBlockedReason( GitHubHead head, GitCommit headCommit, string upgradeBranchPrefix, GitHubProject origin) { if (head.User.Login != origin.Owner) { return($"Owner of head repo '{head.User.Login}' is not '{origin.Owner}'"); } if (!head.Ref.StartsWith(upgradeBranchPrefix)) { return($"Ref name '{head.Ref}' does not start with '{upgradeBranchPrefix}'"); } if (headCommit.Author.Name != GitAuthorName) { return($"Head commit author '{headCommit.Author.Name}' is not '{GitAuthorName}'"); } if (headCommit.Committer.Name != GitAuthorName) { return($"Head commit committer '{headCommit.Committer.Name}' is not '{GitAuthorName}'"); } return(null); }
public async Task CreateOrUpdateAsync( string commitMessage, string title, string description, GitHubBranch baseBranch, GitHubProject origin, PullRequestOptions options) { options = options ?? new PullRequestOptions(); var upstream = baseBranch.Project; using (var client = new GitHubClient(_auth)) { GitHubBranch originBranch = null; GitHubPullRequest pullRequestToUpdate = null; IUpdateBranchNamingStrategy namingStrategy = options.BranchNamingStrategy ?? new SingleBranchNamingStrategy("UpdateDependencies"); string upgradeBranchPrefix = namingStrategy.Prefix(baseBranch.Name); if (!options.ForceCreate) { pullRequestToUpdate = await client.SearchPullRequestsAsync( upstream, upgradeBranchPrefix, _auth.User); if (pullRequestToUpdate == null) { Trace.TraceInformation($"No existing pull request found."); } else { Trace.TraceInformation( $"Pull request already exists for {upgradeBranchPrefix} in {upstream.Segments}. " + $"#{pullRequestToUpdate.Number}, '{pullRequestToUpdate.Title}'"); GitCommit headCommit = await client.GetCommitAsync( origin, pullRequestToUpdate.Head.Sha); string blockedReason = GetUpdateBlockedReason( pullRequestToUpdate, headCommit, upgradeBranchPrefix, origin); if (blockedReason == null) { if (options.TrackDiscardedCommits) { await PostDiscardedCommitCommentAsync( baseBranch.Project, pullRequestToUpdate, headCommit, client); } originBranch = new GitHubBranch( pullRequestToUpdate.Head.Ref, origin); } else { string comment = $"Couldn't update this pull request: {blockedReason}\n" + $"Would have applied '{commitMessage}'"; await client.PostCommentAsync(upstream, pullRequestToUpdate.Number, comment); return; } } } // No existing branch to update: push to a new one. if (originBranch == null) { string newBranchName = namingStrategy.Prefix(baseBranch.Name) + namingStrategy.CreateFreshBranchNameSuffix(baseBranch.Name); originBranch = new GitHubBranch(newBranchName, origin); } PushNewCommit(originBranch, commitMessage); if (pullRequestToUpdate != null) { await client.UpdateGitHubPullRequestAsync( upstream, pullRequestToUpdate.Number, title, description, maintainersCanModify : options.MaintainersCanModify); } else { await client.PostGitHubPullRequestAsync( title, description, originBranch, baseBranch, options.MaintainersCanModify); } } }
protected override void TraceListenedExecute() { // Use the commit sha of versions repo master (not just "master") for stable upgrade. var gitHubAuth = new GitHubAuth(GitHubAuthToken, GitHubUser, GitHubEmail); var client = new GitHubClient(gitHubAuth); string masterSha = client .GetReferenceAsync(new GitHubProject("versions", "dotnet"), "heads/master") .Result.Object.Sha; foreach (ITaskItem item in DependencyBuildInfo) { if (!string.IsNullOrEmpty(item.GetMetadata(CurrentRefMetadataName))) { item.SetMetadata(CurrentRefMetadataName, masterSha); } string autoUpgradeBranch = item.GetMetadata(AutoUpgradeBranchMetadataName); if (!string.IsNullOrEmpty(autoUpgradeBranch)) { item.SetMetadata(CurrentBranchMetadataName, autoUpgradeBranch); } } DependencyUpdateResults updateResults = DependencyUpdateUtils.Update( CreateUpdaters().ToArray(), CreateBuildInfoDependencies().ToArray()); // Update CurrentRef and CurrentBranch for each applicable build info used. if (!string.IsNullOrEmpty(CurrentRefXmlPath)) { foreach (BuildInfo info in updateResults.UsedBuildInfos) { ITaskItem infoItem = FindDependencyBuildInfo(info.Name); if (!string.IsNullOrEmpty(infoItem.GetMetadata(CurrentRefMetadataName))) { UpdateProperty( CurrentRefXmlPath, $"{info.Name}{CurrentRefMetadataName}", masterSha); } string autoUpgradeBranch = infoItem.GetMetadata(AutoUpgradeBranchMetadataName); if (!string.IsNullOrEmpty(autoUpgradeBranch)) { UpdateProperty( CurrentRefXmlPath, $"{info.Name}{CurrentBranchMetadataName}", autoUpgradeBranch); } } } if (updateResults.ChangesDetected()) { var origin = new GitHubProject(ProjectRepoName, GitHubUser); var upstreamBranch = new GitHubBranch( ProjectRepoBranch, new GitHubProject(ProjectRepoName, ProjectRepoOwner)); string suggestedMessage = updateResults.GetSuggestedCommitMessage(); string body = string.Empty; if (NotifyGitHubUsers != null) { body += PullRequestCreator.NotificationString(NotifyGitHubUsers.Select(item => item.ItemSpec)); } var prCreator = new PullRequestCreator(gitHubAuth, origin, upstreamBranch, GitHubAuthor); prCreator.CreateOrUpdateAsync( suggestedMessage, suggestedMessage + $" ({ProjectRepoBranch})", body, forceCreate: AlwaysCreateNewPullRequest).Wait(); } else { Log.LogMessage("No update required: no changes detected."); } }
protected override void TraceListenedExecute() { // Use the commit sha of versions repo master (not just "master") for stable upgrade. var gitHubAuth = new GitHubAuth(GitHubAuthToken, GitHubUser, GitHubEmail); var client = new GitHubClient(gitHubAuth); string masterSha = client .GetReferenceAsync(new GitHubProject("versions", "dotnet"), "heads/master") .Result.Object.Sha; foreach (ITaskItem item in DependencyBuildInfo) { if (!string.IsNullOrEmpty(item.GetMetadata(s_currentRef))) { item.SetMetadata(s_currentRef, masterSha); } } DependencyUpdateResults updateResults = DependencyUpdateUtils.Update( CreateUpdaters().ToArray(), CreateBuildInfoDependencies().ToArray()); if (!string.IsNullOrEmpty(CurrentRefXmlPath)) { // Update the build info commit sha for each applicable build info used. foreach (BuildInfo info in updateResults.UsedBuildInfos) { ITaskItem infoItem = FindDependencyBuildInfo(info.Name); if (string.IsNullOrEmpty(infoItem.GetMetadata(s_currentRef))) { continue; } Regex upgrader = CreateXmlUpdateRegex($"{info.Name}{s_currentRef}", s_currentRef); Action replace = FileUtils.ReplaceFileContents( CurrentRefXmlPath, contents => { Match m = upgrader.Match(contents); Group g = m.Groups[s_currentRef]; return contents .Remove(g.Index, g.Length) .Insert(g.Index, masterSha); }); replace(); } } if (updateResults.ChangesDetected()) { var origin = new GitHubProject(ProjectRepoName, GitHubUser); var upstreamBranch = new GitHubBranch( ProjectRepoBranch, new GitHubProject(ProjectRepoName, ProjectRepoOwner)); string suggestedMessage = updateResults.GetSuggestedCommitMessage(); string body = string.Empty; if (NotifyGitHubUsers != null) { body += PullRequestCreator.NotificationString(NotifyGitHubUsers.Select(item => item.ItemSpec)); } var prCreator = new PullRequestCreator(gitHubAuth, origin, upstreamBranch, GitHubAuthor); prCreator.CreateOrUpdateAsync( suggestedMessage, suggestedMessage + $" ({ProjectRepoBranch})", body, forceCreate: AlwaysCreateNewPullRequest).Wait(); } else { Log.LogMessage("No update required: no changes detected."); } }