Skip to content

Commit c6e9aba

Browse files
committed
Add script regeneration and PR body support in upstream merge
- Run Build.ps1 generate-scripts after Claude conflict resolution - Stage regenerated files before commit - Pass Claude's output as PR body text to GitHub/Azure DevOps APIs
1 parent 6a7af18 commit c6e9aba

File tree

6 files changed

+281
-254
lines changed

6 files changed

+281
-254
lines changed

src/PostSharp.Engineering.BuildTools/ContinuousIntegration/AzureDevOpsHelper.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ private static bool TryConnect( ConsoleHelper console, string url, [NotNullWhen(
4545
AzureDevOpsRepository repository,
4646
string sourceBranch,
4747
string targetBranch,
48-
string title )
48+
string title,
49+
string? body = null )
4950
{
5051
try
5152
{
@@ -60,7 +61,10 @@ private static bool TryConnect( ConsoleHelper console, string url, [NotNullWhen(
6061

6162
var pullRequest = new GitPullRequest()
6263
{
63-
SourceRefName = $"refs/heads/{sourceBranch}", TargetRefName = $"refs/heads/{targetBranch}", Title = title
64+
SourceRefName = $"refs/heads/{sourceBranch}",
65+
TargetRefName = $"refs/heads/{targetBranch}",
66+
Title = title,
67+
Description = body
6468
};
6569

6670
console.WriteMessage( "Creating a pull request." );
Lines changed: 108 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -1,108 +1,109 @@
1-
// Copyright (c) SharpCrafters s.r.o. See the LICENSE.md file in the root directory of this repository root for details.
2-
3-
using PostSharp.Engineering.BuildTools.Build;
4-
using PostSharp.Engineering.BuildTools.ContinuousIntegration.Model;
5-
using PostSharp.Engineering.BuildTools.Tools.TeamCity;
6-
using PostSharp.Engineering.BuildTools.Utilities;
7-
using System;
8-
using System.Diagnostics.CodeAnalysis;
9-
using System.Net.Http;
10-
using System.Net.Http.Headers;
11-
using System.Text;
12-
using System.Text.RegularExpressions;
13-
using System.Threading.Tasks;
14-
15-
namespace PostSharp.Engineering.BuildTools.ContinuousIntegration;
16-
17-
public class AzureDevOpsRepository : VcsRepository
18-
{
19-
// E.g.
20-
// https://postsharp@dev.azure.com/postsharp/Caravela/_git/Caravela.Repo
21-
// https://dev.azure.com/postsharp/Caravela/_git/Caravela.Repo
22-
private static readonly Regex _urlRegex = new(
23-
@"^(?<protocol>https)://(?:(?<user>[^/@]+)@)?(?<domain>[^/]+)/(?<organization>[^/]+)?/(?<project>[^/]+)/_git/(?<repo>[^/]+)$" );
24-
25-
public override string Name { get; }
26-
27-
public override VcsProvider Provider => VcsProvider.AzureDevOps;
28-
29-
public string Domain { get; }
30-
31-
public string Organisation { get; }
32-
33-
public string Project { get; }
34-
35-
public string BaseUrl => $"https://{this.Domain}/{this.Organisation}";
36-
37-
public override string SshUrl => throw new NotImplementedException( "We don't use SSH for Azure DevOps at the moment." );
38-
39-
public override string HttpUrl => $"{this.BaseUrl}/{this.Project}/_git/{this.Name}";
40-
41-
public override string DeveloperMachineRemoteUrl => this.HttpUrl;
42-
43-
public override string TeamCityRemoteUrl => this.HttpUrl;
44-
45-
public override bool IsSshAgentRequired => false;
46-
47-
public override string TokenEnvironmentVariableName => EnvironmentVariableNames.AzureDevOpsToken;
48-
49-
public AzureDevOpsRepository(
50-
string project,
51-
string name,
52-
string organisation = "postsharp",
53-
string domain = "dev.azure.com",
54-
string? defaultBranchParameter = null )
55-
{
56-
this.Name = name;
57-
this.Domain = domain;
58-
this.Organisation = organisation;
59-
this.Project = project;
60-
}
61-
62-
public static bool TryParse( string repoUrl, [NotNullWhen( true )] out AzureDevOpsRepository? repository )
63-
{
64-
var match = _urlRegex.Match( repoUrl );
65-
66-
if ( !match.Success )
67-
{
68-
repository = null;
69-
70-
return false;
71-
}
72-
73-
var name = match.Groups["repo"].Value;
74-
var domain = match.Groups["domain"].Value;
75-
var organisation = match.Groups["organization"].Value;
76-
var project = match.Groups["project"].Value;
77-
repository = new AzureDevOpsRepository( project, name, organisation, domain );
78-
79-
return true;
80-
}
81-
82-
public override bool TryDownloadTextFile( ConsoleHelper console, string branch, string path, [NotNullWhen( true )] out string? text )
83-
{
84-
var httpClient = new HttpClient();
85-
86-
var teamCitySourceReadToken = TeamCityHelper.GetTeamCitySourceReadToken();
87-
88-
var authString = Convert.ToBase64String( Encoding.UTF8.GetBytes( $@"{TeamCityHelper.TeamCityUsername}:{teamCitySourceReadToken}" ) );
89-
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue( "Basic", authString );
90-
91-
var uri = $"{this.BaseUrl}/{this.Project}/_apis/git/repositories/{this.Name}/items?path={path}&versionDescriptor.version={branch}";
92-
93-
console.WriteMessage( $"Downloading {uri}." );
94-
text = httpClient.GetString( uri );
95-
96-
return true;
97-
}
98-
99-
public override Task<bool> TrySetBranchPoliciesAsync( BuildContext context, string buildStatusGenre, string? buildStatusName, bool dry )
100-
=> AzureDevOpsHelper.TrySetBranchPoliciesAsync( context, this, buildStatusGenre, buildStatusName, dry );
101-
102-
public override Task<(bool Success, string? Url, bool RequiresBuild)> TryCreatePullRequestAsync(
103-
ConsoleHelper console,
104-
string sourceBranch,
105-
string targetBranch,
106-
string title )
107-
=> AzureDevOpsHelper.TryCreatePullRequestAsync( console, this, sourceBranch, targetBranch, title );
1+
// Copyright (c) SharpCrafters s.r.o. See the LICENSE.md file in the root directory of this repository root for details.
2+
3+
using PostSharp.Engineering.BuildTools.Build;
4+
using PostSharp.Engineering.BuildTools.ContinuousIntegration.Model;
5+
using PostSharp.Engineering.BuildTools.Tools.TeamCity;
6+
using PostSharp.Engineering.BuildTools.Utilities;
7+
using System;
8+
using System.Diagnostics.CodeAnalysis;
9+
using System.Net.Http;
10+
using System.Net.Http.Headers;
11+
using System.Text;
12+
using System.Text.RegularExpressions;
13+
using System.Threading.Tasks;
14+
15+
namespace PostSharp.Engineering.BuildTools.ContinuousIntegration;
16+
17+
public class AzureDevOpsRepository : VcsRepository
18+
{
19+
// E.g.
20+
// https://postsharp@dev.azure.com/postsharp/Caravela/_git/Caravela.Repo
21+
// https://dev.azure.com/postsharp/Caravela/_git/Caravela.Repo
22+
private static readonly Regex _urlRegex = new(
23+
@"^(?<protocol>https)://(?:(?<user>[^/@]+)@)?(?<domain>[^/]+)/(?<organization>[^/]+)?/(?<project>[^/]+)/_git/(?<repo>[^/]+)$" );
24+
25+
public override string Name { get; }
26+
27+
public override VcsProvider Provider => VcsProvider.AzureDevOps;
28+
29+
public string Domain { get; }
30+
31+
public string Organisation { get; }
32+
33+
public string Project { get; }
34+
35+
public string BaseUrl => $"https://{this.Domain}/{this.Organisation}";
36+
37+
public override string SshUrl => throw new NotImplementedException( "We don't use SSH for Azure DevOps at the moment." );
38+
39+
public override string HttpUrl => $"{this.BaseUrl}/{this.Project}/_git/{this.Name}";
40+
41+
public override string DeveloperMachineRemoteUrl => this.HttpUrl;
42+
43+
public override string TeamCityRemoteUrl => this.HttpUrl;
44+
45+
public override bool IsSshAgentRequired => false;
46+
47+
public override string TokenEnvironmentVariableName => EnvironmentVariableNames.AzureDevOpsToken;
48+
49+
public AzureDevOpsRepository(
50+
string project,
51+
string name,
52+
string organisation = "postsharp",
53+
string domain = "dev.azure.com",
54+
string? defaultBranchParameter = null )
55+
{
56+
this.Name = name;
57+
this.Domain = domain;
58+
this.Organisation = organisation;
59+
this.Project = project;
60+
}
61+
62+
public static bool TryParse( string repoUrl, [NotNullWhen( true )] out AzureDevOpsRepository? repository )
63+
{
64+
var match = _urlRegex.Match( repoUrl );
65+
66+
if ( !match.Success )
67+
{
68+
repository = null;
69+
70+
return false;
71+
}
72+
73+
var name = match.Groups["repo"].Value;
74+
var domain = match.Groups["domain"].Value;
75+
var organisation = match.Groups["organization"].Value;
76+
var project = match.Groups["project"].Value;
77+
repository = new AzureDevOpsRepository( project, name, organisation, domain );
78+
79+
return true;
80+
}
81+
82+
public override bool TryDownloadTextFile( ConsoleHelper console, string branch, string path, [NotNullWhen( true )] out string? text )
83+
{
84+
var httpClient = new HttpClient();
85+
86+
var teamCitySourceReadToken = TeamCityHelper.GetTeamCitySourceReadToken();
87+
88+
var authString = Convert.ToBase64String( Encoding.UTF8.GetBytes( $@"{TeamCityHelper.TeamCityUsername}:{teamCitySourceReadToken}" ) );
89+
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue( "Basic", authString );
90+
91+
var uri = $"{this.BaseUrl}/{this.Project}/_apis/git/repositories/{this.Name}/items?path={path}&versionDescriptor.version={branch}";
92+
93+
console.WriteMessage( $"Downloading {uri}." );
94+
text = httpClient.GetString( uri );
95+
96+
return true;
97+
}
98+
99+
public override Task<bool> TrySetBranchPoliciesAsync( BuildContext context, string buildStatusGenre, string? buildStatusName, bool dry )
100+
=> AzureDevOpsHelper.TrySetBranchPoliciesAsync( context, this, buildStatusGenre, buildStatusName, dry );
101+
102+
public override Task<(bool Success, string? Url, bool RequiresBuild)> TryCreatePullRequestAsync(
103+
ConsoleHelper console,
104+
string sourceBranch,
105+
string targetBranch,
106+
string title,
107+
string? body = null )
108+
=> AzureDevOpsHelper.TryCreatePullRequestAsync( console, this, sourceBranch, targetBranch, title, body );
108109
}

src/PostSharp.Engineering.BuildTools/ContinuousIntegration/GitHubHelper.cs

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,12 @@ public static bool TryDownloadText( ConsoleHelper console, GitHubRepository repo
110110
GitHubRepository repository,
111111
string sourceBranch,
112112
string targetBranch,
113-
string title )
113+
string title,
114+
string? body = null )
114115
{
115-
bool TryConnectRestApis( [NotNullWhen( true )] out GitHubClient? creatorClient, out GitHubClient? reviewerClient )
116+
bool TryConnectRestApis( [NotNullWhen( true )] out GitHubClient? creatorClient )
116117
{
117118
creatorClient = null;
118-
reviewerClient = null;
119119

120120
if ( !TryGetToken( console, out var creatorToken ) )
121121
{
@@ -129,15 +129,12 @@ bool TryConnectRestApis( [NotNullWhen( true )] out GitHubClient? creatorClient,
129129
console.WriteWarning(
130130
$"The {EnvironmentVariableNames.GitHubReviewerToken} environment variable is not defined. The PR won't be auto-approved." );
131131
}
132-
else
133-
{
134-
reviewerClient = creatorToken == reviewerToken ? creatorClient : ConnectRestApi( reviewerToken );
135-
}
132+
else { }
136133

137134
return true;
138135
}
139136

140-
if ( !TryConnectRestApis( out var creatorGitHub, out var reviewerGitHub ) )
137+
if ( !TryConnectRestApis( out var creatorGitHub ) )
141138
{
142139
return default;
143140
}
@@ -157,24 +154,17 @@ bool TryConnectRestApis( [NotNullWhen( true )] out GitHubClient? creatorClient,
157154
else
158155
{
159156
console.WriteMessage( "Creating pull request." );
160-
var newPullRequest = new NewPullRequest( title, sourceBranch, targetBranch );
157+
var newPullRequest = new NewPullRequest( title, sourceBranch, targetBranch ) { Body = body };
161158
pullRequest = await creatorGitHub.PullRequest.Create( repository.Owner, repository.Name, newPullRequest );
162159
console.WriteMessage( $"Pull request created: {pullRequest.Url}" );
163160
}
164161

165-
// A pull request cannot be self-reviewed on GitHub.
166-
// https://github.com/orgs/community/discussions/6292
167-
if ( reviewerGitHub != null )
168-
{
162+
/*
169163
var reviewerLogin = reviewerGitHub.User.Current().Result.Login;
170164
console.WriteMessage( $"Requesting a review of the pull request from '{reviewerLogin}' user." );
171165
var reviewRequest = new PullRequestReviewRequest( new List<string> { reviewerLogin }, new List<string>() );
172166
pullRequest = await reviewerGitHub.PullRequest.ReviewRequest.Create( repository.Owner, repository.Name, pullRequest.Number, reviewRequest );
173-
174-
console.WriteMessage( "Approving the pull request." );
175-
var pullRequestApproval = new PullRequestReviewCreate { Event = PullRequestReviewEvent.Approve };
176-
_ = await reviewerGitHub.PullRequest.Review.Create( repository.Owner, repository.Name, pullRequest.Number, pullRequestApproval );
177-
}
167+
*/
178168

179169
// Check if the PR is in a clean state before enabling auto-merge.
180170
// Connect to REST API to get latest PR details.

0 commit comments

Comments
 (0)