Skip to content

Commit 1dcab16

Browse files
mitchdennyMitch DennyCopilot
authored
Fix CopilotCliRunner version parsing for 'GitHub Copilot CLI X.X.X' format (#14568)
* Fix CopilotCliRunner version parsing for 'GitHub Copilot CLI X.X.X' format Extract version parsing into a testable TryParseVersionOutput method that handles prefixed version strings like 'GitHub Copilot CLI 0.0.397' by taking the last space-separated token before parsing. Fixes #14174 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR feedback: handle trailing punctuation in version string Trim trailing period and other punctuation before parsing, to handle output like 'GitHub Copilot CLI 0.0.397.' from the issue report. Add test case for the trailing period format. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Mitch Denny <mitch@mitchdeny.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent f3d3d63 commit 1dcab16

File tree

2 files changed

+70
-21
lines changed

2 files changed

+70
-21
lines changed

src/Aspire.Cli/Agents/CopilotCli/CopilotCliRunner.cs

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -52,28 +52,8 @@ internal sealed class CopilotCliRunner(ILogger<CopilotCliRunner> logger) : ICopi
5252
}
5353

5454
var output = await outputTask.ConfigureAwait(false);
55-
var versionString = output.Trim();
5655

57-
if (string.IsNullOrEmpty(versionString))
58-
{
59-
logger.LogDebug("GitHub Copilot CLI returned empty version output");
60-
return null;
61-
}
62-
63-
// Version output may be on the first line if multi-line
64-
var lines = versionString.Split(['\n', '\r'], StringSplitOptions.RemoveEmptyEntries);
65-
if (lines.Length > 0)
66-
{
67-
versionString = lines[0].Trim();
68-
}
69-
70-
// Try to parse the version string (may have a 'v' prefix like "v1.2.3")
71-
if (versionString.StartsWith('v') || versionString.StartsWith('V'))
72-
{
73-
versionString = versionString[1..];
74-
}
75-
76-
if (SemVersion.TryParse(versionString, SemVersionStyles.Any, out var version))
56+
if (TryParseVersionOutput(output, out var version))
7757
{
7858
logger.LogDebug("Found GitHub Copilot CLI version: {Version}", version);
7959
return version;
@@ -88,4 +68,40 @@ internal sealed class CopilotCliRunner(ILogger<CopilotCliRunner> logger) : ICopi
8868
return null;
8969
}
9070
}
71+
72+
internal static bool TryParseVersionOutput(string output, out SemVersion? version)
73+
{
74+
version = null;
75+
var versionString = output.Trim();
76+
77+
if (string.IsNullOrEmpty(versionString))
78+
{
79+
return false;
80+
}
81+
82+
// Version output may be on the first line if multi-line
83+
var lines = versionString.Split(['\n', '\r'], StringSplitOptions.RemoveEmptyEntries);
84+
if (lines.Length > 0)
85+
{
86+
versionString = lines[0].Trim();
87+
}
88+
89+
// Try to extract the version from known formats like "GitHub Copilot CLI 0.0.397"
90+
var lastSpaceIndex = versionString.LastIndexOf(' ');
91+
if (lastSpaceIndex >= 0)
92+
{
93+
versionString = versionString[(lastSpaceIndex + 1)..];
94+
}
95+
96+
// Trim common trailing punctuation that may follow the version (for example, "0.0.397.")
97+
versionString = versionString.TrimEnd('.', ',', ')');
98+
99+
// Try to parse the version string (may have a 'v' prefix like "v1.2.3")
100+
if (versionString.StartsWith('v') || versionString.StartsWith('V'))
101+
{
102+
versionString = versionString[1..];
103+
}
104+
105+
return SemVersion.TryParse(versionString, SemVersionStyles.Any, out version);
106+
}
91107
}

tests/Aspire.Cli.Tests/Agents/CopilotCliRunnerTests.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,37 @@ public async Task GetVersionAsync_ChecksForCopilot()
2424
// we just verify the method completes without throwing
2525
// Version can be null (not installed) or a real version
2626
}
27+
28+
[Theory]
29+
[InlineData("GitHub Copilot CLI 0.0.397", 0, 0, 397)]
30+
[InlineData("GitHub Copilot CLI 1.2.3", 1, 2, 3)]
31+
[InlineData("0.0.397", 0, 0, 397)]
32+
[InlineData("1.2.3", 1, 2, 3)]
33+
[InlineData("v1.2.3", 1, 2, 3)]
34+
[InlineData("V1.2.3", 1, 2, 3)]
35+
[InlineData("GitHub Copilot CLI 0.0.397\nsome other output", 0, 0, 397)]
36+
[InlineData(" GitHub Copilot CLI 0.0.397 ", 0, 0, 397)]
37+
[InlineData("GitHub Copilot CLI 0.0.397.", 0, 0, 397)]
38+
public void TryParseVersionOutput_ValidVersionStrings_ReturnsTrue(string input, int major, int minor, int patch)
39+
{
40+
var result = CopilotCliRunner.TryParseVersionOutput(input, out var version);
41+
42+
Assert.True(result);
43+
Assert.NotNull(version);
44+
Assert.Equal(major, version.Major);
45+
Assert.Equal(minor, version.Minor);
46+
Assert.Equal(patch, version.Patch);
47+
}
48+
49+
[Theory]
50+
[InlineData("")]
51+
[InlineData(" ")]
52+
[InlineData("not a version")]
53+
public void TryParseVersionOutput_InvalidVersionStrings_ReturnsFalse(string input)
54+
{
55+
var result = CopilotCliRunner.TryParseVersionOutput(input, out var version);
56+
57+
Assert.False(result);
58+
Assert.Null(version);
59+
}
2760
}

0 commit comments

Comments
 (0)