Skip to content

Commit 38af79f

Browse files
agocke333fred
andauthored
Support tracking feature channels (#186) (#187)
I would find it useful, so I implemented it. (cherry picked from commit e8b17b8) Co-authored-by: Fred Silberberg <frsilb@microsoft.com>
1 parent 823306d commit 38af79f

File tree

7 files changed

+87
-20
lines changed

7 files changed

+87
-20
lines changed

src/dnvm/Channel.cs

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ public static class Channels
1313
{
1414
public static string GetDesc(this Channel c) => c switch
1515
{
16-
Channel.Versioned v => $"The latest version in the {v} support channel",
16+
Channel.VersionedMajorMinor v => $"The latest version in the {v} support channel",
17+
Channel.VersionedFeature v => $"The latest version in the {v} support channel",
1718
Channel.Lts => "The latest version in Long-Term support",
1819
Channel.Sts => "The latest version in Short-Term support",
1920
Channel.Latest => "The latest supported version from either the LTS or STS support channels.",
@@ -30,7 +31,12 @@ private Channel() { }
3031
/// <summary>
3132
/// A major-minor versioned channel.
3233
/// </summary>
33-
public sealed partial record Versioned(int Major, int Minor) : Channel;
34+
public sealed partial record VersionedMajorMinor(int Major, int Minor) : Channel;
35+
/// <summary>
36+
/// A major-minor-patch versioned channel.
37+
/// </summary>
38+
/// <param name="FeatureLevel"> The feature level of the version, e.g. 1 in 9.0.100</param>
39+
public sealed partial record VersionedFeature(int Major, int Minor, int FeatureLevel) : Channel;
3440
/// <summary>
3541
/// Newest Long Term Support release.
3642
/// </summary>
@@ -67,10 +73,14 @@ void ISerialize<Channel>.Serialize(Channel channel, ISerializer serializer)
6773
=> serializer.SerializeString(channel.GetLowerName());
6874
}
6975

70-
partial record Versioned
76+
partial record VersionedMajorMinor
7177
{
7278
public override string GetDisplayName() => $"{Major}.{Minor}";
7379
}
80+
partial record VersionedFeature
81+
{
82+
public override string GetDisplayName() => $"{Major}.{Minor}.{FeatureLevel}xx";
83+
}
7484
partial record Lts : Channel
7585
{
7686
public override string GetDisplayName() => "LTS";
@@ -103,13 +113,24 @@ public static Channel FromString(string str)
103113
case "preview": return new Preview();
104114
default:
105115
var components = str.Split('.');
106-
if (components.Length != 2)
116+
switch (components)
107117
{
108-
throw new DeserializeException($"Invalid channel version: {str}");
118+
case [_, _]:
119+
var major = int.Parse(components[0]);
120+
var minor = int.Parse(components[1]);
121+
return new VersionedMajorMinor(major, minor);
122+
case [_, _, _]:
123+
if (components[2] is not [<= '9' and >= '0', 'x', 'x'])
124+
{
125+
throw new DeserializeException($"Feature band must be 3 characters and end in 'xx': {str}");
126+
}
127+
major = int.Parse(components[0]);
128+
minor = int.Parse(components[1]);
129+
var featureLevel = components[2][0] - '0';
130+
return new VersionedFeature(major, minor, featureLevel);
131+
default:
132+
throw new DeserializeException($"Invalid channel version: {str}");
109133
}
110-
var major = int.Parse(components[0]);
111-
var minor = int.Parse(components[1]);
112-
return new Versioned(major, minor);
113134
}
114135
}
115136

src/dnvm/DotnetReleasesIndex.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ await CancelScope.WithTimeoutAfter(DnvmEnv.DefaultTimeout,
6363
or (Channel.Sts, "active", "sts")
6464
or (Channel.Preview, "go-live", _)
6565
or (Channel.Preview, "preview", _) => true,
66-
(Channel.Versioned v, _, _) when v.ToString() == releaseVersion.ToMajorMinor() => true,
66+
(Channel.VersionedMajorMinor v, _, _) when v.ToString() == releaseVersion.ToMajorMinor() => true,
67+
(Channel.VersionedFeature v, _, _) when v.ToString() == releaseVersion.ToFeature() => true,
6768
_ => false
6869
};
6970
if (found &&
@@ -163,4 +164,4 @@ public partial record File
163164
public required string Rid { get; init; }
164165
public string? Hash { get; init; } = null;
165166
}
166-
}
167+
}

src/dnvm/InstallCommand.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public static async Task<Result> Run(DnvmEnv env, Logger logger, CommandArgument
4545
}
4646

4747
var sdkVersion = options.SdkVersion;
48-
var channel = new Channel.Versioned(sdkVersion.Major, sdkVersion.Minor);
48+
var channel = new Channel.VersionedMajorMinor(sdkVersion.Major, sdkVersion.Minor);
4949

5050
if (!options.Force && manifest.InstalledSdks.Any(s => s.SdkVersion == sdkVersion && s.SdkDirName == sdkDir))
5151
{
@@ -351,4 +351,4 @@ @echo off
351351
}
352352
}
353353
}
354-
}
354+
}

src/dnvm/TrackCommand.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ internal static async Task<Result> InstallLatestFromChannel(
148148
// 2. The channel is supported but there are currently no builds available
149149
// We want to provide a helpful error message about the first case, but let the second
150150
// case go through without attempting to install anything.
151-
if (channel is Channel.Versioned)
151+
if (channel is Channel.VersionedMajorMinor or Channel.VersionedFeature)
152152
{
153153
logger.Error($"Could not find channel '{channel}' in the dotnet releases index.");
154154
return Result.UnknownChannel;

src/dnvm/Utilities/Utilities.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,17 @@ public static void ChmodExec(IFileSystem vfs, UPath upath)
159159

160160
public static string ToMajorMinor(this SemVersion version) => $"{version.Major}.{version.Minor}";
161161

162+
public static string ToFeature(this SemVersion version)
163+
{
164+
int feature = version.Patch;
165+
while (feature >= 10)
166+
{
167+
feature /= 10;
168+
}
169+
170+
return $"{version.Major}.{version.Minor}.{feature}xx";
171+
}
172+
162173
public static string SeqToString<T>(this IEnumerable<T> e)
163174
{
164175
return "[ " + string.Join(", ", e) + " ]";
@@ -337,4 +348,4 @@ public override string ToString()
337348
Libc.Musl => string.Join('-', os, arch, "musl")
338349
};
339350
}
340-
}
351+
}

test/UnitTests/CommandLineTests.cs

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,16 +86,33 @@ public void TrackMajorMinor()
8686
"99.99"
8787
]);
8888
Assert.True(options!.Command is CommandArguments.TrackArguments {
89-
Channel: Channel.Versioned { Major: 99, Minor: 99 }
89+
Channel: Channel.VersionedMajorMinor { Major: 99, Minor: 99 }
9090
});
9191
}
9292

9393
[Fact]
94-
public void TrackBadChannel()
94+
public void TrackFeature()
95+
{
96+
var options = CommandLineArguments.ParseRaw(new TestConsole(), [
97+
"track",
98+
"99.99.9xx"
99+
]);
100+
Assert.True(options!.Command is CommandArguments.TrackArguments {
101+
Channel: Channel.VersionedFeature { Major: 99, Minor: 99, FeatureLevel: 9 }
102+
});
103+
}
104+
105+
[Theory]
106+
[InlineData("badchannel")]
107+
[InlineData("99.99.9x")]
108+
[InlineData("99.99.9xxx")]
109+
[InlineData("99.99.900")]
110+
[InlineData("99.99.axx")]
111+
public void TrackBadChannel(string channel)
95112
{
96113
var ex = Assert.Throws<ArgumentSyntaxException>(() => CommandLineArguments.ParseRaw(new TestConsole(), [
97114
"track",
98-
"badversion"
115+
channel
99116
]));
100117
var tab = "\t";
101118
Assert.Equal($"""
@@ -440,4 +457,4 @@ to the .dotnet folder in the same directory.
440457
441458
""".NormalizeLineEndings(), console.Output.TrimLines());
442459
}
443-
}
460+
}

test/UnitTests/TrackTests.cs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,24 @@ public Task ChannelOverlap() => RunWithServer(async (server, env) =>
156156
[Fact]
157157
public Task TrackMajorMinor() => RunWithServer(async (server, env) =>
158158
{
159-
var result = await TrackCommand.Run(env, _logger, new() { Channel = new Channel.Versioned(99, 99) });
159+
var result = await TrackCommand.Run(env, _logger, new() { Channel = new Channel.VersionedMajorMinor(99, 99) });
160+
Assert.Equal(TrackCommand.Result.Success, result);
161+
162+
var manifest = await env.ReadManifest();
163+
var version = SemVersion.Parse("99.99.99-preview", SemVersionStyles.Strict);
164+
Assert.Equal([ new() {
165+
ReleaseVersion = version,
166+
SdkVersion = version,
167+
RuntimeVersion = version,
168+
AspNetVersion = version,
169+
SdkDirName = DnvmEnv.DefaultSdkDirName
170+
} ], manifest.InstalledSdks);
171+
});
172+
173+
[Fact]
174+
public Task TrackFeature() => RunWithServer(async (server, env) =>
175+
{
176+
var result = await TrackCommand.Run(env, _logger, new() { Channel = new Channel.VersionedFeature(99, 99, 9) });
160177
Assert.Equal(TrackCommand.Result.Success, result);
161178

162179
var manifest = await env.ReadManifest();
@@ -219,4 +236,4 @@ public Task TrackNoBuilds() => RunWithServer(async (mockServer, env) =>
219236
InstalledSdkVersions = [ ]
220237
}], manifest.RegisteredChannels);
221238
});
222-
}
239+
}

0 commit comments

Comments
 (0)