Skip to content

Commit e0a10ab

Browse files
committed
Fixing Metalama.Compiler dependencies. Improving downstream merge.
1 parent 4c499f8 commit e0a10ab

File tree

9 files changed

+117
-47
lines changed

9 files changed

+117
-47
lines changed

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ private static bool TryConnect( ConsoleHelper console, string url, [NotNullWhen(
4040
// https://github.com/microsoft/azure-devops-dotnet-samples/blob/main/ClientLibrary/Samples/Git/PullRequestsSample.cs
4141
// https://stackoverflow.com/a/52025418/4100001
4242
// Required personal access token scopes: Code: Read&Write
43-
public static async Task<string?> TryCreatePullRequestAsync(
43+
public static async Task<(bool Success, string? Url, bool RequiresBuild)> TryCreatePullRequestAsync(
4444
ConsoleHelper console,
4545
AzureDevOpsRepository repository,
4646
string sourceBranch,
@@ -51,7 +51,7 @@ private static bool TryConnect( ConsoleHelper console, string url, [NotNullWhen(
5151
{
5252
if ( !TryConnect( console, repository.BaseUrl, out var azureDevOps ) )
5353
{
54-
return null;
54+
return default;
5555
}
5656

5757
using ( azureDevOps )
@@ -91,14 +91,14 @@ private static bool TryConnect( ConsoleHelper console, string url, [NotNullWhen(
9191

9292
var url = $"{repository.BaseUrl}/{repository.Project}/_git/{repository.Name}/pullrequest/{createdPullRequest.PullRequestId}";
9393

94-
return url;
94+
return (true, url, true);
9595
}
9696
}
9797
catch ( Exception e )
9898
{
9999
console.WriteError( e.ToString() );
100100

101-
return null;
101+
return default;
102102
}
103103
}
104104

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ public override bool TryDownloadTextFile( ConsoleHelper console, string branch,
9999
public override Task<bool> TrySetBranchPoliciesAsync( BuildContext context, string buildStatusGenre, string? buildStatusName, bool dry )
100100
=> AzureDevOpsHelper.TrySetBranchPoliciesAsync( context, this, buildStatusGenre, buildStatusName, dry );
101101

102-
public override Task<string?> TryCreatePullRequestAsync( ConsoleHelper console, string sourceBranch, string targetBranch, string title )
102+
public override Task<(bool Success, string? Url, bool RequiresBuild)> TryCreatePullRequestAsync(
103+
ConsoleHelper console,
104+
string sourceBranch,
105+
string targetBranch,
106+
string title )
103107
=> AzureDevOpsHelper.TryCreatePullRequestAsync( console, this, sourceBranch, targetBranch, title );
104108
}

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

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ public static bool TryDownloadText( ConsoleHelper console, GitHubRepository repo
102102
return true;
103103
}
104104

105-
public static async Task<string?> TryCreatePullRequestAsync(
105+
public static async Task<(bool Success, string? Url, bool RequiresBuild)> TryCreatePullRequestAsync(
106106
ConsoleHelper console,
107107
GitHubRepository repository,
108108
string sourceBranch,
@@ -136,12 +136,12 @@ bool TryConnectRestApis( [NotNullWhen( true )] out GitHubClient? creatorClient,
136136

137137
if ( !TryConnectRestApis( out var creatorGitHub, out var reviewerGitHub ) )
138138
{
139-
return null;
139+
return default;
140140
}
141141

142142
if ( !TryConnectGraphQl( console, out var graphQl ) )
143143
{
144-
return null;
144+
return default;
145145
}
146146

147147
var allExistingPullRequests = await creatorGitHub.PullRequest.GetAllForRepository( repository.Owner, repository.Name );
@@ -173,7 +173,48 @@ bool TryConnectRestApis( [NotNullWhen( true )] out GitHubClient? creatorClient,
173173
_ = await reviewerGitHub.PullRequest.Review.Create( repository.Owner, repository.Name, pullRequest.Number, pullRequestApproval );
174174
}
175175

176-
console.WriteMessage( "Enabling pull request auto-merge." );
176+
// Check if the PR is in a clean state before enabling auto-merge.
177+
// Connect to REST API to get latest PR details.
178+
if ( !TryConnectRestApi( console, out var restClient ) )
179+
{
180+
console.WriteError( "Could not connect to GitHub REST API." );
181+
182+
return default;
183+
}
184+
185+
var latestPr = await restClient.PullRequest.Get( repository.Owner, repository.Name, pullRequest.Number );
186+
var isMergeable = latestPr.Mergeable == true;
187+
188+
// Check status checks (if any required)
189+
var combinedStatus = await restClient.Repository.Status.GetCombined( repository.Owner, repository.Name, latestPr.Head.Sha );
190+
var isClean = isMergeable && combinedStatus.State.Value == CommitState.Success;
191+
192+
if ( isClean )
193+
{
194+
console.WriteMessage( "PR is in a clean state. Merging directly." );
195+
196+
// Directly merge the PR.
197+
var mergeResult = await restClient.PullRequest.Merge(
198+
repository.Owner,
199+
repository.Name,
200+
pullRequest.Number,
201+
new MergePullRequest { CommitTitle = title, MergeMethod = Octokit.PullRequestMergeMethod.Merge } );
202+
203+
if ( mergeResult.Merged )
204+
{
205+
console.WriteMessage( "PR merged successfully." );
206+
var url = $"https://github.com/{repository.Owner}/{repository.Name}/pull/{pullRequest.Number}";
207+
208+
return (true, url, false);
209+
}
210+
else
211+
{
212+
console.WriteError( "Failed to merge PR directly. Proceeding to enable auto-merge." );
213+
}
214+
}
215+
216+
// Enable auto-merge.
217+
console.WriteMessage( "PR is not in a clean state. Enabling pull request auto-merge." );
177218

178219
var pullRequestQuery = new Query()
179220
.RepositoryOwner( repository.Owner )
@@ -193,14 +234,14 @@ bool TryConnectRestApis( [NotNullWhen( true )] out GitHubClient? creatorClient,
193234
{
194235
AuthorEmail = authorEmail, CommitHeadline = title, MergeMethod = PullRequestMergeMethod.Merge, PullRequestId = pullRequestId
195236
} ) )
196-
.Select( am => am.ClientMutationId ) // We need to select something to avoid ResponseDeserializerException
237+
.Select( am => am.ClientMutationId )
197238
.Compile();
198239

199240
_ = await graphQl.Run( enableAutoMergeMutation );
200241

201-
var url = $"https://github.com/{repository.Owner}/{repository.Name}/pull/{pullRequest.Number}";
242+
var finalUrl = $"https://github.com/{repository.Owner}/{repository.Name}/pull/{pullRequest.Number}";
202243

203-
return url;
244+
return (true, finalUrl, true);
204245
}
205246

206247
public static async Task<bool> TrySetBranchPoliciesAsync(

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ public override bool TryDownloadTextFile( ConsoleHelper console, string branch,
6464
public override Task<bool> TrySetBranchPoliciesAsync( BuildContext context, string buildStatusGenre, string? buildStatusName, bool dry )
6565
=> GitHubHelper.TrySetBranchPoliciesAsync( context, this, buildStatusGenre, buildStatusName, dry );
6666

67-
public override Task<string?> TryCreatePullRequestAsync( ConsoleHelper console, string sourceBranch, string targetBranch, string title )
67+
public override Task<(bool Success, string? Url, bool RequiresBuild)> TryCreatePullRequestAsync(
68+
ConsoleHelper console,
69+
string sourceBranch,
70+
string targetBranch,
71+
string title )
6872
=> GitHubHelper.TryCreatePullRequestAsync( console, this, sourceBranch, targetBranch, title );
6973
}

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,11 @@ public abstract class VcsRepository
3939

4040
public abstract Task<bool> TrySetBranchPoliciesAsync( BuildContext context, string buildStatusGenre, string? buildStatusName, bool dry );
4141

42-
public abstract Task<string?> TryCreatePullRequestAsync( ConsoleHelper console, string sourceBranch, string targetBranch, string title );
42+
public abstract Task<(bool Success, string? Url, bool RequiresBuild)> TryCreatePullRequestAsync(
43+
ConsoleHelper console,
44+
string sourceBranch,
45+
string targetBranch,
46+
string title );
4347

4448
/// <summary>
4549
/// Returns the URL that identifies the repository and allows user to access the repository using a web browser.

src/PostSharp.Engineering.BuildTools/Dependencies/Definitions/MetalamaDependencies.V2025_1.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ public MetalamaDependencyDefinition(
6969
{
7070
EngineeringDirectory = "eng-Metalama",
7171
#pragma warning disable CS0618 // Type or member is obsolete
72-
ParametricPrivateArtifactsDirectory = Path.Combine( "artifacts", "packages", "$(MSBuildConfiguration)", "Shipping" )
72+
ParametricPrivateArtifactsDirectory = Path.Combine( "artifacts", "packages", "$(MSBuildConfiguration)", "Shipping" ),
73+
Dependencies = [DevelopmentDependencies.PostSharpEngineering]
7374
#pragma warning restore CS0618 // Type or member is obsolete
7475
};
7576

src/PostSharp.Engineering.BuildTools/Dependencies/Definitions/MetalamaDependencies.V2025_2.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,9 @@ public MetalamaDependencyDefinition(
6868
{
6969
EngineeringDirectory = "eng-Metalama",
7070
#pragma warning disable CS0618 // Type or member is obsolete
71-
ParametricPrivateArtifactsDirectory = Path.Combine( "artifacts", "packages", "$(MSBuildConfiguration)", "Shipping" )
71+
ParametricPrivateArtifactsDirectory = Path.Combine( "artifacts", "packages", "$(MSBuildConfiguration)", "Shipping" ),
7272
#pragma warning restore CS0618 // Type or member is obsolete
73+
Dependencies = [DevelopmentDependencies.PostSharpEngineering]
7374
};
7475

7576
public static DependencyDefinition Metalama { get; } =

src/PostSharp.Engineering.BuildTools/Dependencies/Definitions/MetalamaDependencies.V2026_0.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,9 @@ public MetalamaDependencyDefinition(
7070
{
7171
EngineeringDirectory = "eng-Metalama",
7272
#pragma warning disable CS0618 // Type or member is obsolete
73-
ParametricPrivateArtifactsDirectory = Path.Combine( "artifacts", "packages", "$(MSBuildConfiguration)", "Shipping" )
73+
ParametricPrivateArtifactsDirectory = Path.Combine( "artifacts", "packages", "$(MSBuildConfiguration)", "Shipping" ),
7474
#pragma warning restore CS0618 // Type or member is obsolete
75+
Dependencies = [DevelopmentDependencies.PostSharpEngineering]
7576
};
7677

7778
public static DependencyDefinition Metalama { get; } =

src/PostSharp.Engineering.BuildTools/Tools/Git/DownstreamMerge.cs

Lines changed: 44 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -325,26 +325,29 @@ public static bool MergeDownstream( BuildContext context, DownstreamMergeSetting
325325

326326
if ( isPullRequestRequired )
327327
{
328-
if ( !TryCreatePullRequest( context, targetBranch, downstreamBranch, sourceBranch, out var pullRequestUrl ) )
328+
if ( !TryCreatePullRequest( context, targetBranch, downstreamBranch, sourceBranch, out var pullRequestUrl, out var requiresBuild ) )
329329
{
330330
return false;
331331
}
332332

333333
context.Console.WriteSuccess( $"Created pull request: {pullRequestUrl}" );
334334

335-
if ( !TryScheduleBuild(
336-
downstreamDependencyDefinition.CiConfiguration,
337-
context.Console,
338-
targetBranch,
339-
sourceBranch,
340-
pullRequestUrl,
341-
pullRequestStatusCheckBuildTypeId!, // Checked by isPullRequestRequired
342-
out var buildUrl ) )
335+
if ( requiresBuild )
343336
{
344-
return false;
345-
}
337+
if ( !TryScheduleBuild(
338+
downstreamDependencyDefinition.CiConfiguration,
339+
context.Console,
340+
targetBranch,
341+
sourceBranch,
342+
pullRequestUrl,
343+
pullRequestStatusCheckBuildTypeId!, // Checked by isPullRequestRequired
344+
out var buildUrl ) )
345+
{
346+
return false;
347+
}
346348

347-
context.Console.WriteSuccess( $"Scheduled build: {buildUrl}" );
349+
context.Console.WriteSuccess( $"Scheduled build: {buildUrl}" );
350+
}
348351
}
349352

350353
return true;
@@ -447,56 +450,67 @@ private static bool TryCreatePullRequest(
447450
string targetBranch,
448451
string downstreamBranch,
449452
string sourceBranch,
450-
[NotNullWhen( true )] out string? pullRequestUrl )
453+
[NotNullWhen( true )] out string? pullRequestUrl,
454+
out bool requiresBuild )
451455
{
452456
context.Console.WriteImportantMessage( $"Creating pull request from '{targetBranch}' branch to '{downstreamBranch}' downstream branch" );
453457

454458
if ( !GitHelper.TryGetRemoteUrl( context, out var remoteUrl ) )
455459
{
456460
pullRequestUrl = null;
461+
requiresBuild = false;
457462

458463
return false;
459464
}
460465

461466
try
462467
{
463468
var pullRequestTitle = $"Downstream merge from '{sourceBranch}' branch";
464-
Task<string?> newPullRequestTask;
469+
470+
(bool Success, string? Url, bool RequiresBuild) newPullRequest;
465471

466472
if ( VcsUrlParser.TryGetRepository( remoteUrl, out var repository ) )
467473
{
468-
newPullRequestTask = repository.TryCreatePullRequestAsync(
469-
context.Console,
470-
targetBranch,
471-
downstreamBranch,
472-
pullRequestTitle );
474+
newPullRequest = repository.TryCreatePullRequestAsync(
475+
context.Console,
476+
targetBranch,
477+
downstreamBranch,
478+
pullRequestTitle )
479+
.ConfigureAwait( false )
480+
.GetAwaiter()
481+
.GetResult();
482+
483+
if ( !newPullRequest.Success )
484+
{
485+
pullRequestUrl = null;
486+
requiresBuild = false;
487+
488+
return false;
489+
}
490+
491+
context.Console.WriteImportantMessage( $"Pull request created. {newPullRequest.Url}" );
492+
requiresBuild = newPullRequest.RequiresBuild;
493+
pullRequestUrl = newPullRequest.Url!;
494+
495+
return true;
473496
}
474497
else
475498
{
476499
context.Console.WriteError( $"Unknown VCS or unexpected repo URL format. Repo URL: '{remoteUrl}'." );
477500
pullRequestUrl = null;
501+
requiresBuild = false;
478502

479503
return false;
480504
}
481-
482-
pullRequestUrl = newPullRequestTask.ConfigureAwait( false ).GetAwaiter().GetResult();
483-
484-
if ( pullRequestUrl == null )
485-
{
486-
return false;
487-
}
488505
}
489506
catch ( Exception e )
490507
{
491508
context.Console.WriteError( e.ToString() );
492509
pullRequestUrl = null;
510+
requiresBuild = false;
493511

494512
return false;
495513
}
496-
497-
context.Console.WriteImportantMessage( $"Pull request created. {pullRequestUrl}" );
498-
499-
return true;
500514
}
501515

502516
private static bool TryScheduleBuild(

0 commit comments

Comments
 (0)