-
Notifications
You must be signed in to change notification settings - Fork 95
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
nuke target for verifying .NET SDK versions used (#3727)
- Loading branch information
Showing
13 changed files
with
377 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
name: SdkVersionCheck | ||
|
||
on: | ||
push: | ||
branches: [ main ] | ||
pull_request: | ||
merge_group: | ||
workflow_dispatch: | ||
|
||
jobs: | ||
check-sdk-versions: | ||
runs-on: windows-latest | ||
steps: | ||
|
||
- name: Checkout | ||
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # tag: v4.2.1 | ||
|
||
- name: Setup .NET 8 | ||
uses: actions/setup-dotnet@6bd8b7f7774af54e05809fcc5431931b3eb1ddee # tag: v4.0.1 | ||
with: | ||
dotnet-version: 8.0.403 | ||
|
||
- name: Run VerifySdkVersions | ||
run: ./build.cmd VerifySdkVersions |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
using YamlDotNet.RepresentationModel; | ||
|
||
namespace SdkVersionVerifier; | ||
|
||
internal static class ActionWorkflowVerifier | ||
{ | ||
public static DotnetSdkVersion? GetExpectedSdkVersionFromSampleWorkflow(string root) | ||
{ | ||
var defaultWorkflow = Path.Combine(GetWorkflowsDirectory(root), "build.yml"); | ||
return ExtractDotnetSdkVersions(File.ReadAllText(defaultWorkflow)).FirstOrDefault(); | ||
} | ||
|
||
public static bool VerifyVersions(string root, DotnetSdkVersion expectedDotnetSdkVersion) | ||
{ | ||
var workflowsDir = GetWorkflowsDirectory(root); | ||
var workflows = Directory.GetFiles(workflowsDir, "*.yml"); | ||
|
||
return FileVerifier.VerifyMultiple(workflows, VerifySdkVersions, expectedDotnetSdkVersion); | ||
} | ||
|
||
private static string GetWorkflowsDirectory(string root) | ||
{ | ||
return Path.Combine(root, ".github", "workflows"); | ||
} | ||
|
||
private static bool VerifySdkVersions(string content, DotnetSdkVersion expectedDotnetSdkVersion) | ||
{ | ||
foreach (var extractedSdkVersion in ExtractDotnetSdkVersions(content)) | ||
{ | ||
if (!VersionComparer.CompareVersions(expectedDotnetSdkVersion, extractedSdkVersion)) | ||
{ | ||
return false; | ||
} | ||
} | ||
|
||
return true; | ||
} | ||
|
||
private static IEnumerable<DotnetSdkVersion> ExtractDotnetSdkVersions(string content) | ||
{ | ||
var workflow = new YamlStream(); | ||
using var stringReader = new StringReader(content); | ||
workflow.Load(stringReader); | ||
|
||
var jobs = ExtractJobs(workflow); | ||
foreach (var job in jobs) | ||
{ | ||
if (!job.Children.TryGetValue(new YamlScalarNode("steps"), out var stepsNode)) | ||
{ | ||
continue; | ||
} | ||
|
||
foreach (var step in (YamlSequenceNode)stepsNode) | ||
{ | ||
var jobStepNode = (YamlMappingNode)step; | ||
if (jobStepNode.Children.TryGetValue(new YamlScalarNode("uses"), out var usesNode) && usesNode.ToString().StartsWith("actions/setup-dotnet")) | ||
{ | ||
var withNode = (YamlMappingNode)jobStepNode.Children[new YamlScalarNode("with")]; | ||
var dotnetVersionNode = (YamlScalarNode)withNode.Children[new YamlScalarNode("dotnet-version")]; | ||
|
||
var extractedVersion = ExtractVersion(dotnetVersionNode); | ||
if (extractedVersion is not null) | ||
{ | ||
yield return extractedVersion; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
private static DotnetSdkVersion? ExtractVersion(YamlScalarNode dotnetVersionNode) | ||
{ | ||
// Extract versions from the node value e.g.: | ||
// dotnet-version: | | ||
// 6.0.427 | ||
// 7.0.410 | ||
// 8.0.403 | ||
|
||
string? sdk6Version = null; | ||
string? sdk7Version = null; | ||
string? sdk8Version = null; | ||
|
||
foreach (var version in dotnetVersionNode.ToString().Split()) | ||
{ | ||
if (version.StartsWith('6')) | ||
{ | ||
sdk6Version = version; | ||
} | ||
|
||
if (version.StartsWith('7')) | ||
{ | ||
sdk7Version = version; | ||
} | ||
|
||
if (version.StartsWith('8')) | ||
{ | ||
sdk8Version = version; | ||
} | ||
} | ||
|
||
if (sdk6Version is not null || sdk7Version is not null || sdk8Version is not null) | ||
{ | ||
return new DotnetSdkVersion(sdk6Version, sdk7Version, sdk8Version); | ||
} | ||
|
||
return null; | ||
} | ||
|
||
private static IEnumerable<YamlMappingNode> ExtractJobs(YamlStream yaml) | ||
{ | ||
var rootNode = yaml.Documents[0].RootNode as YamlMappingNode; | ||
var jobsNode = (YamlMappingNode)rootNode!.Children[new YamlScalarNode("jobs")]; | ||
return jobsNode.Children.Select(j => (YamlMappingNode)j.Value); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
using System.Text.RegularExpressions; | ||
using dockerfile; | ||
|
||
namespace SdkVersionVerifier; | ||
|
||
internal static partial class DockerfileVerifier | ||
{ | ||
public static bool VerifyVersions(string root, DotnetSdkVersion expectedDotnetSdkVersion) | ||
{ | ||
var dockerfilesDir = Path.Combine(root, "docker"); | ||
var dockerfiles = Directory.GetFiles(dockerfilesDir, "*.dockerfile"); | ||
|
||
return FileVerifier.VerifyMultiple(dockerfiles, VerifyVersionsFromDockerfiles, expectedDotnetSdkVersion); | ||
} | ||
|
||
[GeneratedRegex(@"-v (\d\.\d\.\d{3})\s", RegexOptions.IgnoreCase, "en-US")] | ||
internal static partial Regex VersionRegex(); | ||
|
||
private static bool VerifyVersionsFromDockerfiles(string content, DotnetSdkVersion expectedDotnetSdkVersion) | ||
{ | ||
using var stringReader = new StringReader(content); | ||
var dockerfile = Dockerfile.Parse(stringReader); | ||
|
||
string? net6SdkVersion = null; | ||
string? net7SdkVersion = null; | ||
string? net8SdkVersion = null; | ||
|
||
foreach (var instruction in dockerfile.Instructions.Where(i => i.Arguments.Contains("./dotnet-install.sh"))) | ||
{ | ||
// Extract version from line like `&& ./dotnet-install.sh -v 6.0.427 --install-dir /usr/share/dotnet --no-path \` | ||
var result = VersionRegex().Match(instruction.Arguments); | ||
if (!result.Success) | ||
{ | ||
continue; | ||
} | ||
|
||
var extractedSdkVersion = result.Groups[1].Value; | ||
if (extractedSdkVersion.StartsWith('6')) | ||
{ | ||
net6SdkVersion = extractedSdkVersion; | ||
} | ||
else if (extractedSdkVersion.StartsWith('7')) | ||
{ | ||
net7SdkVersion = extractedSdkVersion; | ||
} | ||
} | ||
|
||
// Extract NET8 SDK version from the base image tag | ||
// e.g. FROM mcr.microsoft.com/dotnet/sdk:8.0.403-alpine3.20 | ||
var fromInstruction = dockerfile.Instructions | ||
.SingleOrDefault(i => i.InstructionName == "FROM" && i.Arguments.StartsWith("mcr.microsoft.com/dotnet/sdk")); | ||
|
||
if (fromInstruction is not null) | ||
{ | ||
net8SdkVersion = fromInstruction.Arguments.Split(':')[1].Split('-')[0]; | ||
} | ||
|
||
return VersionComparer.CompareVersions(expectedDotnetSdkVersion, net6SdkVersion, net7SdkVersion, net8SdkVersion); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
namespace SdkVersionVerifier; | ||
|
||
internal record DotnetSdkVersion(string? Net6SdkVersion, string? Net7SdkVersion, string? Net8SdkVersion); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
namespace SdkVersionVerifier; | ||
|
||
internal static class FileVerifier | ||
{ | ||
public static bool VerifyMultiple( | ||
IEnumerable<string> filePaths, | ||
Func<string, DotnetSdkVersion, bool> versionPredicate, | ||
DotnetSdkVersion dotnetSdkVersion) | ||
{ | ||
foreach (var filePath in filePaths) | ||
{ | ||
Console.WriteLine($"Verifying SDK versions from {filePath}"); | ||
var content = File.ReadAllText(filePath); | ||
var versionsMatch = versionPredicate(content, dotnetSdkVersion); | ||
if (versionsMatch) | ||
{ | ||
continue; | ||
} | ||
|
||
Console.WriteLine($"Invalid SDK versions in {filePath}"); | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
namespace SdkVersionVerifier; | ||
|
||
internal static class Program | ||
{ | ||
public static int Main(string[] args) | ||
{ | ||
if (args.Length != 1) | ||
{ | ||
Console.WriteLine("Invalid arguments. Single argument with repository root is required."); | ||
return 1; | ||
} | ||
|
||
var directoryRoot = args[0]; | ||
|
||
// Set expected dotnet SDK versions based on sample workflow. | ||
// This set of versions will be expected to be used consistently | ||
// in GitHub actions workflows and dockerfiles. | ||
var expectedVersion = ActionWorkflowVerifier.GetExpectedSdkVersionFromSampleWorkflow(directoryRoot); | ||
if (expectedVersion is null) | ||
{ | ||
Console.WriteLine("Unable to extract expected SDK version from sample workflow file."); | ||
return 1; | ||
} | ||
|
||
Console.WriteLine($"Expected SDK versions: {expectedVersion}"); | ||
if (!ActionWorkflowVerifier.VerifyVersions(directoryRoot, expectedVersion)) | ||
{ | ||
Console.WriteLine("Invalid SDK versions in GitHub actions workflows."); | ||
return 1; | ||
} | ||
|
||
if (!DockerfileVerifier.VerifyVersions(directoryRoot, expectedVersion)) | ||
{ | ||
Console.WriteLine("Invalid SDK versions in dockerfiles."); | ||
return 1; | ||
} | ||
|
||
return 0; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"$schema": "http://json.schemastore.org/launchsettings.json", | ||
"profiles": { | ||
"SdkVersionVerifier": { | ||
"commandName": "Project", | ||
"commandLineArgs": "$(SolutionDir)", | ||
"environmentVariables": { | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>net8.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
<OutputType>Exe</OutputType> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="Dockerfile" /> | ||
<PackageReference Include="YamlDotNet" /> | ||
</ItemGroup> | ||
|
||
</Project> |
Oops, something went wrong.