Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

.NET 8 OS compatibility test #3422

Merged
merged 3 commits into from
Aug 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Runner.Common/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,8 @@ public static class System
public static readonly string PhaseDisplayName = "system.phaseDisplayName";
public static readonly string JobRequestType = "system.jobRequestType";
public static readonly string OrchestrationId = "system.orchestrationId";
public static readonly string TestDotNet8Compatibility = "system.testDotNet8Compatibility";
public static readonly string DotNet8CompatibilityWarning = "system.dotNet8CompatibilityWarning";
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/Runner.Worker/JobExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ public async Task<List<IStep>> InitializeJob(IExecutionContext jobContext, Pipel

// Check OS warning
var osWarningChecker = HostContext.GetService<IOSWarningChecker>();
await osWarningChecker.CheckOSAsync(context, message.OSWarnings);
await osWarningChecker.CheckOSAsync(context);

try
{
Expand Down
113 changes: 61 additions & 52 deletions src/Runner.Worker/OSWarningChecker.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Text.RegularExpressions;
using GitHub.DistributedTask.WebApi;
using GitHub.DistributedTask.Pipelines;
using GitHub.Runner.Common;
using GitHub.Runner.Sdk;

Expand All @@ -13,75 +12,85 @@ namespace GitHub.Runner.Worker
[ServiceLocator(Default = typeof(OSWarningChecker))]
public interface IOSWarningChecker : IRunnerService
{
Task CheckOSAsync(IExecutionContext context, IList<OSWarning> osWarnings);
Task CheckOSAsync(IExecutionContext context);
}

#if OS_WINDOWS || OS_OSX
public sealed class OSWarningChecker : RunnerService, IOSWarningChecker
{
public Task CheckOSAsync(IExecutionContext context, IList<OSWarning> osWarnings)
public async Task CheckOSAsync(IExecutionContext context)
{
ArgUtil.NotNull(context, nameof(context));
ArgUtil.NotNull(osWarnings, nameof(osWarnings));
return Task.CompletedTask;
}
}
#else
public sealed class OSWarningChecker : RunnerService, IOSWarningChecker
{
private static readonly TimeSpan s_matchTimeout = TimeSpan.FromMilliseconds(100);
private static readonly RegexOptions s_regexOptions = RegexOptions.CultureInvariant | RegexOptions.IgnoreCase;

public async Task CheckOSAsync(IExecutionContext context, IList<OSWarning> osWarnings)
{
ArgUtil.NotNull(context, nameof(context));
ArgUtil.NotNull(osWarnings, nameof(osWarnings));
foreach (var osWarning in osWarnings)
if (!context.Global.Variables.System_TestDotNet8Compatibility)
{
if (string.IsNullOrEmpty(osWarning.FilePath))
{
Trace.Error("The file path is not specified in the OS warning check.");
continue;
}
return;
}

if (string.IsNullOrEmpty(osWarning.RegularExpression))
context.Output("Testing runner upgrade compatibility");
List<string> output = new();
object outputLock = new();
try
{
using (var process = HostContext.CreateService<IProcessInvoker>())
{
Trace.Error("The regular expression is not specified in the OS warning check.");
continue;
}
process.OutputDataReceived += delegate (object sender, ProcessDataReceivedEventArgs stdout)
{
if (!string.IsNullOrEmpty(stdout.Data))
{
lock (outputLock)
{
output.Add(stdout.Data);
Trace.Info(stdout.Data);
}
}
};

if (string.IsNullOrEmpty(osWarning.Warning))
{
Trace.Error("The warning message is not specified in the OS warning check.");
continue;
}
process.ErrorDataReceived += delegate (object sender, ProcessDataReceivedEventArgs stderr)
{
if (!string.IsNullOrEmpty(stderr.Data))
{
lock (outputLock)
{
output.Add(stderr.Data);
Trace.Error(stderr.Data);
}
}
};

try
{
if (File.Exists(osWarning.FilePath))
using (var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(10)))
{
var lines = await File.ReadAllLinesAsync(osWarning.FilePath, context.CancellationToken);
var regex = new Regex(osWarning.RegularExpression, s_regexOptions, s_matchTimeout);
foreach (var line in lines)
int exitCode = await process.ExecuteAsync(
workingDirectory: HostContext.GetDirectory(WellKnownDirectory.Root),
fileName: Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Bin), "testDotNet8Compatibility", $"TestDotNet8Compatibility{IOUtil.ExeExtension}"),
arguments: string.Empty,
environment: null,
cancellationToken: cancellationTokenSource.Token);

var outputStr = string.Join("\n", output).Trim();
if (exitCode != 0 || !string.Equals(outputStr, "Hello from .NET 8!", StringComparison.Ordinal))
{
if (regex.IsMatch(line))
var warningMessage = context.Global.Variables.System_DotNet8CompatibilityWarning;
if (!string.IsNullOrEmpty(warningMessage))
{
context.Warning(osWarning.Warning);
context.Global.JobTelemetry.Add(new JobTelemetry() { Type = JobTelemetryType.General, Message = $"OS warning: {osWarning.Warning}" });
return;
context.Warning(warningMessage);
}

context.Global.JobTelemetry.Add(new JobTelemetry() { Type = JobTelemetryType.General, Message = $".NET 8 OS compatibility test failed with exit code '{exitCode}' and output: {GetShortOutput(output)}" });
}
}
}
catch (Exception ex)
{
Trace.Error("An error occurred while checking OS warnings for file '{0}' and regex '{1}'.", osWarning.FilePath, osWarning.RegularExpression);
Trace.Error(ex);
context.Global.JobTelemetry.Add(new JobTelemetry() { Type = JobTelemetryType.General, Message = $"An error occurred while checking OS warnings for file '{osWarning.FilePath}' and regex '{osWarning.RegularExpression}': {ex.Message}" });
}
}
catch (Exception ex)
{
Trace.Error("An error occurred while testing .NET 8 compatibility'");
Trace.Error(ex);
context.Global.JobTelemetry.Add(new JobTelemetry() { Type = JobTelemetryType.General, Message = $".NET 8 OS compatibility test encountered exception type '{ex.GetType().FullName}', message: '{ex.Message}', process output: '{GetShortOutput(output)}'" });
}
}

private static string GetShortOutput(List<string> output)
{
var outputStr = string.Join("\n", output).Trim();
return outputStr.Length > 200 ? string.Concat(outputStr.Substring(0, 200), "[...]") : outputStr;
}
}
#endif
}

4 changes: 4 additions & 0 deletions src/Runner.Worker/Variables.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,12 @@ public Variables(IHostContext hostContext, IDictionary<string, VariableValue> co

public bool? Step_Debug => GetBoolean(Constants.Variables.Actions.StepDebug);

public string System_DotNet8CompatibilityWarning => Get(Constants.Variables.System.DotNet8CompatibilityWarning);

public string System_PhaseDisplayName => Get(Constants.Variables.System.PhaseDisplayName);

public bool System_TestDotNet8Compatibility => GetBoolean(Constants.Variables.System.TestDotNet8Compatibility) ?? false;

public string Get(string name)
{
Variable variable;
Expand Down
26 changes: 0 additions & 26 deletions src/Sdk/DTPipelines/Pipelines/AgentJobRequestMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ public AgentJobRequestMessage(
IList<TemplateToken> defaults,
ActionsEnvironmentReference actionsEnvironment,
TemplateToken snapshot,
IList<OSWarning> osWarnings,
String messageType = JobRequestMessageTypes.PipelineAgentJobRequest)
{
this.MessageType = messageType;
Expand Down Expand Up @@ -74,11 +73,6 @@ public AgentJobRequestMessage(
m_defaults = new List<TemplateToken>(defaults);
}

if (osWarnings?.Count > 0)
{
m_osWarnings = new List<OSWarning>(osWarnings);
}

this.ContextData = new Dictionary<String, PipelineContextData>(StringComparer.OrdinalIgnoreCase);
if (contextData?.Count > 0)
{
Expand Down Expand Up @@ -294,18 +288,6 @@ public IList<String> FileTable
}
}

public IList<OSWarning> OSWarnings
{
get
{
if (m_osWarnings == null)
{
m_osWarnings = new List<OSWarning>();
}
return m_osWarnings;
}
}

// todo: remove after feature-flag DistributedTask.EvaluateContainerOnRunner is enabled everywhere
public void SetJobSidecarContainers(IDictionary<String, String> value)
{
Expand Down Expand Up @@ -443,11 +425,6 @@ private void OnSerializing(StreamingContext context)
{
JobContainer = new StringToken(null, null, null, m_jobContainerResourceAlias);
}

if (m_osWarnings?.Count == 0)
{
m_osWarnings = null;
}
}

[DataMember(Name = "EnvironmentVariables", EmitDefaultValue = false)]
Expand All @@ -472,9 +449,6 @@ private void OnSerializing(StreamingContext context)
[DataMember(Name = "JobSidecarContainers", EmitDefaultValue = false)]
private IDictionary<String, String> m_jobSidecarContainers;

[DataMember(Name = "OSWarnings", EmitDefaultValue = false)]
private List<OSWarning> m_osWarnings;

// todo: remove after feature-flag DistributedTask.EvaluateContainerOnRunner is enabled everywhere
[IgnoreDataMember]
private string m_jobContainerResourceAlias;
Expand Down
44 changes: 0 additions & 44 deletions src/Sdk/DTPipelines/Pipelines/OSWarning.cs

This file was deleted.

3 changes: 1 addition & 2 deletions src/Test/L0/Listener/JobDispatcherL0.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ private Pipelines.AgentJobRequestMessage CreateJobRequestMessage()
TaskOrchestrationPlanReference plan = new();
TimelineReference timeline = null;
Guid jobId = Guid.NewGuid();
var result = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, "someJob", "someJob", null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null, null, null);
var result = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, "someJob", "someJob", null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null, null);
result.ContextData["github"] = new Pipelines.ContextData.DictionaryContextData();
return result;
}
Expand Down Expand Up @@ -810,7 +810,6 @@ private static AgentJobRequestMessage GetAgentJobRequestMessage()
null,
new List<TemplateToken>(),
new ActionsEnvironmentReference("env"),
null,
null
);
return message;
Expand Down
2 changes: 1 addition & 1 deletion src/Test/L0/Listener/RunnerL0.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ private Pipelines.AgentJobRequestMessage CreateJobRequestMessage(string jobName)
TaskOrchestrationPlanReference plan = new();
TimelineReference timeline = null;
Guid jobId = Guid.NewGuid();
return new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, "test", "test", null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null, null, null);
return new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, "test", "test", null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null, null);
}

private JobCancelMessage CreateJobCancelMessage()
Expand Down
2 changes: 1 addition & 1 deletion src/Test/L0/Worker/ActionCommandManagerL0.cs
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ public void EchoProcessCommandDebugOn()
TimelineReference timeline = new();
Guid jobId = Guid.NewGuid();
string jobName = "some job name";
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null, null, null);
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null, null);
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
{
Alias = Pipelines.PipelineConstants.SelfAlias,
Expand Down
2 changes: 1 addition & 1 deletion src/Test/L0/Worker/CreateStepSummaryCommandL0.cs
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ private TestHostContext Setup([CallerMemberName] string name = "")
TimelineReference timeline = new();
Guid jobId = Guid.NewGuid();
string jobName = "Summary Job";
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null, null, null);
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null, null);
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
{
Alias = Pipelines.PipelineConstants.SelfAlias,
Expand Down
Loading
Loading