Skip to content

Commit 6a7af18

Browse files
committed
Fix Claude CLI invocation and upstream merge push step
- Use claude.cmd instead of claude for Windows compatibility - Fix double backslash escaping in NodeJs ENV paths - Remove premature push step in upstream merge workflow
1 parent 06bcdf3 commit 6a7af18

File tree

3 files changed

+98
-109
lines changed

3 files changed

+98
-109
lines changed

src/PostSharp.Engineering.BuildTools/Docker/NodeJsComponent.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ public override void WriteDockerfile( TextWriter writer )
3030
Rename-Item "C:\node-v{{version}}-win-x64" "C:\nodejs"; `
3131
Remove-Item node.zip
3232
33-
ENV NPM_CONFIG_PREFIX=C:\\npm
34-
ENV PATH="C:\nodejs;C:\\npm;${PATH}"
33+
ENV NPM_CONFIG_PREFIX=C:\npm
34+
ENV PATH="C:\nodejs;C:\npm;${PATH}"
3535
""" );
3636
}
3737
}

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

Lines changed: 18 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,8 @@ public static bool CheckUpstreamChanges( BuildContext context, BaseBuildSettings
8383

8484
context.Console.WriteMessage( "Step 2 complete: No unmerged upstream commits found." );
8585

86-
context.Console.WriteSuccess( settings.Force ? "Pending upstream changes check completed (some issues ignored due to --force)." : "No pending upstream changes found." );
86+
context.Console.WriteSuccess(
87+
settings.Force ? "Pending upstream changes check completed (some issues ignored due to --force)." : "No pending upstream changes found." );
8788

8889
return true;
8990
}
@@ -318,8 +319,11 @@ public static bool MergeUpstream( BuildContext context, UpstreamMergeSettings se
318319
if ( upstreamBranch == currentBranch )
319320
{
320321
context.Console.WriteError( $"BUG: Upstream branch '{upstreamBranch}' is the same as current branch '{currentBranch}'!" );
321-
context.Console.WriteError( $"This indicates a configuration issue. The upstream product family ({upstreamProductFamily.Version}) " +
322-
$"returned a DependencyDefinition from family version {upstreamDependencyDefinition.ProductFamily.Version}." );
322+
323+
context.Console.WriteError(
324+
$"This indicates a configuration issue. The upstream product family ({upstreamProductFamily.Version}) " +
325+
$"returned a DependencyDefinition from family version {upstreamDependencyDefinition.ProductFamily.Version}." );
326+
323327
context.Console.WriteError( "Check that the product is properly defined in each ProductFamily version." );
324328

325329
return false;
@@ -333,8 +337,7 @@ public static bool MergeUpstream( BuildContext context, UpstreamMergeSettings se
333337

334338
if ( context.Branch != currentBranch )
335339
{
336-
context.Console.WriteError(
337-
$"Upstream merge must be executed on the downstream development branch ('{currentBranch}')." );
340+
context.Console.WriteError( $"Upstream merge must be executed on the downstream development branch ('{currentBranch}')." );
338341
context.Console.WriteError( $"Currently on branch '{context.Branch}'." );
339342
context.Console.WriteError( $"Please checkout '{currentBranch}' and try again." );
340343

@@ -462,8 +465,8 @@ public static bool MergeUpstream( BuildContext context, UpstreamMergeSettings se
462465
// These are obsolete and should be deleted to avoid confusion
463466
var formerMergeBranches = references.Where( r => r.Reference != targetBranchReference )
464467
.Where( r => r.Reference.StartsWith(
465-
$"refs/heads/merge/{currentProductFamily.Version}/{upstreamProductFamily.Version}-",
466-
StringComparison.OrdinalIgnoreCase ) )
468+
$"refs/heads/merge/{currentProductFamily.Version}/{upstreamProductFamily.Version}-",
469+
StringComparison.OrdinalIgnoreCase ) )
467470
.ToArray();
468471

469472
if ( formerMergeBranches.Length == 0 )
@@ -546,23 +549,11 @@ public static bool MergeUpstream( BuildContext context, UpstreamMergeSettings se
546549

547550
context.Console.WriteMessage( "Successfully created merge branch." );
548551

549-
// ==================== STEP 14: Push Merge Branch ====================
550-
context.Console.WriteMessage( "" );
551-
context.Console.WriteMessage( "Step 14: Pushing merge branch to remote..." );
552-
context.Console.WriteMessage( "This ensures the branch exists on remote before we start merging." );
553-
554-
if ( !GitHelper.TryPush( context ) )
555-
{
556-
context.Console.WriteError( "Failed to push merge branch." );
557-
558-
return false;
559-
}
560-
561552
context.Console.WriteMessage( "Merge branch pushed successfully." );
562553

563-
// ==================== STEP 15: Perform the Merge ====================
554+
// ==================== STEP 14: Perform the Merge ====================
564555
context.Console.WriteMessage( "" );
565-
context.Console.WriteMessage( "Step 15: Performing the merge..." );
556+
context.Console.WriteMessage( "Step 14: Performing the merge..." );
566557

567558
if ( !TryMerge( context, upstreamBranch, targetBranch, currentBranch, out var areChangesPending, out var prBodyText ) )
568559
{
@@ -579,12 +570,11 @@ public static bool MergeUpstream( BuildContext context, UpstreamMergeSettings se
579570
return true;
580571
}
581572

582-
context.Console.WriteSuccess(
583-
$"Merge completed! Changes from '{upstreamBranch}' have been merged into '{targetBranch}'." );
573+
context.Console.WriteSuccess( $"Merge completed! Changes from '{upstreamBranch}' have been merged into '{targetBranch}'." );
584574

585-
// ==================== STEP 16: Create Pull Request ====================
575+
// ==================== STEP 17: Create Pull Request ====================
586576
context.Console.WriteMessage( "" );
587-
context.Console.WriteMessage( "Step 16: Creating pull request..." );
577+
context.Console.WriteMessage( "Step 17: Creating pull request..." );
588578

589579
if ( !TryCreatePullRequest( context, targetBranch, currentBranch, upstreamBranch, prBodyText, out var pullRequestUrl ) )
590580
{
@@ -593,9 +583,9 @@ public static bool MergeUpstream( BuildContext context, UpstreamMergeSettings se
593583
return false;
594584
}
595585

596-
// ==================== STEP 17: Schedule Build ====================
586+
// ==================== STEP 18: Schedule Build ====================
597587
context.Console.WriteMessage( "" );
598-
context.Console.WriteMessage( "Step 17: Scheduling build on merge branch..." );
588+
context.Console.WriteMessage( "Step 18: Scheduling build on merge branch..." );
599589

600590
if ( !TryScheduleBuild(
601591
product.DependencyDefinition.CiConfiguration,
@@ -1042,4 +1032,4 @@ void Write( string message )
10421032

10431033
Write( "" );
10441034
}
1045-
}
1035+
}

src/PostSharp.Engineering.BuildTools/Utilities/ClaudeCodeHelper.cs

Lines changed: 78 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ public static bool TryResolveMergeConflicts(
7878
var maskedEnvVars = MaskSecretEnvironmentVariables();
7979
console.WriteMessage( $"Masked {maskedEnvVars.Count( kv => kv.Value == "<redacted>" )} secret variable(s)." );
8080

81-
8281
// Build the command arguments
8382
// -p: Print mode - required for piped input, outputs to stdout
8483
// --output-format stream-json: Stream JSON events in real-time
@@ -143,7 +142,7 @@ void HandleOutput( string line )
143142
// Invoke claude with custom output handler
144143
var success = ToolInvocationHelper.InvokeTool(
145144
console,
146-
"claude",
145+
"claude.cmd",
147146
claudeArgs,
148147
workingDirectory,
149148
out var exitCode,
@@ -424,7 +423,7 @@ private static string RestructureOutputForPR( string output )
424423
/// </summary>
425424
private static HashSet<string> GetSecretEnvironmentVariableNames()
426425
{
427-
return typeof( EnvironmentVariableNames )
426+
return typeof(EnvironmentVariableNames)
428427
.GetFields( BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static )
429428
.Where( f => f.GetCustomAttribute<SecretAttribute>() != null )
430429
.Select( f => (string) f.GetValue( null )! )
@@ -434,80 +433,80 @@ private static HashSet<string> GetSecretEnvironmentVariableNames()
434433
private static string BuildMergeConflictPrompt( string sourceBranch, string targetBranch )
435434
{
436435
return $"""
437-
# Merge Conflict Resolution Task
438-
439-
You are resolving merge conflicts from branch '{sourceBranch}' (upstream) into '{targetBranch}' (current).
440-
This is a NON-INTERACTIVE session - you must complete the task without asking questions.
441-
442-
## Your Goal
443-
Resolve all merge conflicts so the merge can proceed. You do NOT need to build - the PR build will verify compilation.
444-
445-
## Generated Files (can be ignored)
446-
The following files are auto-generated. If they have conflicts, you can resolve them by keeping EITHER version
447-
(preferably the current/HEAD version). They will be regenerated when the PR build runs.
448-
- Build.ps1
449-
- DockerBuild.ps1
450-
- Dockerfile
451-
- Dockerfile.claude
452-
- .teamcity/settings.kts
453-
- .teamcity/pom.xml
454-
- eng/Versions.*.g.props
455-
- eng/DockerMounts.g.ps1
456-
457-
## Step-by-Step Process
458-
459-
### 1. Assess the situation
460-
Run `git status` to see which files have conflicts (marked as "both modified" or "unmerged").
461-
462-
### 2. For EACH conflicting file:
463-
a) Read the file to see the conflict markers (<<<<<<<, =======, >>>>>>>)
464-
b) Understand what each side of the conflict is trying to do:
465-
- The section after <<<<<<< HEAD is the current branch ({targetBranch})
466-
- The section after ======= is from the incoming branch ({sourceBranch})
467-
c) Decide the correct resolution:
468-
- If both changes are needed, combine them logically
469-
- If one supersedes the other, keep the appropriate one
470-
- Consider the semantic meaning, not just the text
471-
- For generated files (see list above), just keep HEAD version
472-
d) Edit the file to remove ALL conflict markers and leave only the resolved code
473-
e) Run `git add <file>` to mark it as resolved
474-
475-
### 3. Final check
476-
Run `git status` to confirm all conflicts are resolved and files are staged.
477-
478-
## Conflict Resolution Rules
479-
- **Package versions**: When there's a conflict in package/dependency versions (in Directory.Packages.props, .csproj, etc.), always choose the HIGHER version number
480-
- **Code conflicts**: Analyze the intent of both changes and merge them logically
481-
- **Generated files**: Keep HEAD version, they will be regenerated by the PR build
482-
483-
## Important Constraints
484-
- Do NOT run `git commit` - leave that to the calling process
485-
- Do NOT run `git push`
486-
- Do NOT build the code - the PR build will handle compilation
487-
- Do NOT modify files that don't have conflicts
488-
- If you encounter a conflict you cannot resolve confidently, resolve it to the best of your ability and note it in your output
489-
490-
## Success Criteria
491-
- All conflict markers removed from all files
492-
- All previously conflicting files staged with `git add`
493-
- `git status` shows no unmerged files
494-
495-
## Output Format
496-
At the very end of your work, write a conclusion block in this exact format:
497-
498-
```
499-
===CONCLUSION===
500-
[One-paragraph summary of what was merged and any notable decisions made]
501-
502-
Files resolved:
503-
- file1.cs: [brief description of resolution]
504-
- file2.csproj: [brief description of resolution]
505-
===END_CONCLUSION===
506-
```
507-
508-
This conclusion will be extracted and placed at the TOP of the PR description.
509-
510-
Begin now.
511-
""";
436+
# Merge Conflict Resolution Task
437+
438+
You are resolving merge conflicts from branch '{sourceBranch}' (upstream) into '{targetBranch}' (current).
439+
This is a NON-INTERACTIVE session - you must complete the task without asking questions.
440+
441+
## Your Goal
442+
Resolve all merge conflicts so the merge can proceed. You do NOT need to build - the PR build will verify compilation.
443+
444+
## Generated Files (can be ignored)
445+
The following files are auto-generated. If they have conflicts, you can resolve them by keeping EITHER version
446+
(preferably the current/HEAD version). They will be regenerated when the PR build runs.
447+
- Build.ps1
448+
- DockerBuild.ps1
449+
- Dockerfile
450+
- Dockerfile.claude
451+
- .teamcity/settings.kts
452+
- .teamcity/pom.xml
453+
- eng/Versions.*.g.props
454+
- eng/DockerMounts.g.ps1
455+
456+
## Step-by-Step Process
457+
458+
### 1. Assess the situation
459+
Run `git status` to see which files have conflicts (marked as "both modified" or "unmerged").
460+
461+
### 2. For EACH conflicting file:
462+
a) Read the file to see the conflict markers (<<<<<<<, =======, >>>>>>>)
463+
b) Understand what each side of the conflict is trying to do:
464+
- The section after <<<<<<< HEAD is the current branch ({targetBranch})
465+
- The section after ======= is from the incoming branch ({sourceBranch})
466+
c) Decide the correct resolution:
467+
- If both changes are needed, combine them logically
468+
- If one supersedes the other, keep the appropriate one
469+
- Consider the semantic meaning, not just the text
470+
- For generated files (see list above), just keep HEAD version
471+
d) Edit the file to remove ALL conflict markers and leave only the resolved code
472+
e) Run `git add <file>` to mark it as resolved
473+
474+
### 3. Final check
475+
Run `git status` to confirm all conflicts are resolved and files are staged.
476+
477+
## Conflict Resolution Rules
478+
- **Package versions**: When there's a conflict in package/dependency versions (in Directory.Packages.props, .csproj, etc.), always choose the HIGHER version number
479+
- **Code conflicts**: Analyze the intent of both changes and merge them logically
480+
- **Generated files**: Keep HEAD version, they will be regenerated by the PR build
481+
482+
## Important Constraints
483+
- Do NOT run `git commit` - leave that to the calling process
484+
- Do NOT run `git push`
485+
- Do NOT build the code - the PR build will handle compilation
486+
- Do NOT modify files that don't have conflicts
487+
- If you encounter a conflict you cannot resolve confidently, resolve it to the best of your ability and note it in your output
488+
489+
## Success Criteria
490+
- All conflict markers removed from all files
491+
- All previously conflicting files staged with `git add`
492+
- `git status` shows no unmerged files
493+
494+
## Output Format
495+
At the very end of your work, write a conclusion block in this exact format:
496+
497+
```
498+
===CONCLUSION===
499+
[One-paragraph summary of what was merged and any notable decisions made]
500+
501+
Files resolved:
502+
- file1.cs: [brief description of resolution]
503+
- file2.csproj: [brief description of resolution]
504+
===END_CONCLUSION===
505+
```
506+
507+
This conclusion will be extracted and placed at the TOP of the PR description.
508+
509+
Begin now.
510+
""";
512511
}
513-
}
512+
}

0 commit comments

Comments
 (0)