2024-08-02 14:37:46 -05:00
using System ;
using System.Collections.Generic ;
using System.IO ;
2024-08-13 09:02:26 -05:00
using System.Text.RegularExpressions ;
2024-08-07 16:53:00 -05:00
using System.Threading ;
2024-08-02 14:37:46 -05:00
using System.Threading.Tasks ;
using GitHub.DistributedTask.WebApi ;
using GitHub.Runner.Common ;
using GitHub.Runner.Sdk ;
namespace GitHub.Runner.Worker
{
[ServiceLocator(Default = typeof(OSWarningChecker))]
public interface IOSWarningChecker : IRunnerService
{
2024-08-07 16:53:00 -05:00
Task CheckOSAsync ( IExecutionContext context ) ;
2024-08-02 14:37:46 -05:00
}
public sealed class OSWarningChecker : RunnerService , IOSWarningChecker
{
2024-08-13 09:02:26 -05:00
private static TimeSpan s_regexTimeout = TimeSpan . FromSeconds ( 1 ) ;
2024-08-07 16:53:00 -05:00
public async Task CheckOSAsync ( IExecutionContext context )
2024-08-02 14:37:46 -05:00
{
ArgUtil . NotNull ( context , nameof ( context ) ) ;
2024-08-07 16:53:00 -05:00
if ( ! context . Global . Variables . System_TestDotNet8Compatibility )
2024-08-02 14:37:46 -05:00
{
2024-08-07 16:53:00 -05:00
return ;
}
2024-08-02 14:37:46 -05:00
2024-08-07 16:53:00 -05:00
context . Output ( "Testing runner upgrade compatibility" ) ;
List < string > output = new ( ) ;
object outputLock = new ( ) ;
try
{
using ( var process = HostContext . CreateService < IProcessInvoker > ( ) )
2024-08-02 14:37:46 -05:00
{
2024-08-07 16:53:00 -05:00
process . OutputDataReceived + = delegate ( object sender , ProcessDataReceivedEventArgs stdout )
{
if ( ! string . IsNullOrEmpty ( stdout . Data ) )
{
lock ( outputLock )
{
output . Add ( stdout . Data ) ;
Trace . Info ( stdout . Data ) ;
}
}
} ;
2024-08-02 14:37:46 -05:00
2024-08-07 16:53:00 -05:00
process . ErrorDataReceived + = delegate ( object sender , ProcessDataReceivedEventArgs stderr )
{
if ( ! string . IsNullOrEmpty ( stderr . Data ) )
{
lock ( outputLock )
{
output . Add ( stderr . Data ) ;
Trace . Error ( stderr . Data ) ;
}
}
} ;
2024-08-02 14:37:46 -05:00
2024-08-07 16:53:00 -05:00
using ( var cancellationTokenSource = new CancellationTokenSource ( TimeSpan . FromSeconds ( 10 ) ) )
2024-08-02 14:37:46 -05:00
{
2024-08-07 16:53:00 -05:00
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 ) )
2024-08-02 14:37:46 -05:00
{
2024-08-13 09:02:26 -05:00
var pattern = context . Global . Variables . System_DotNet8CompatibilityOutputPattern ;
if ( ! string . IsNullOrEmpty ( pattern ) )
{
var regex = new Regex ( pattern , RegexOptions . IgnoreCase | RegexOptions . CultureInvariant , s_regexTimeout ) ;
if ( ! regex . IsMatch ( outputStr ) )
{
return ;
}
}
2024-08-07 16:53:00 -05:00
var warningMessage = context . Global . Variables . System_DotNet8CompatibilityWarning ;
if ( ! string . IsNullOrEmpty ( warningMessage ) )
2024-08-02 14:37:46 -05:00
{
2024-08-07 16:53:00 -05:00
context . Warning ( warningMessage ) ;
2024-08-02 14:37:46 -05:00
}
2024-08-07 16:53:00 -05:00
2024-08-13 09:02:26 -05:00
context . Global . JobTelemetry . Add ( new JobTelemetry ( ) { Type = JobTelemetryType . General , Message = $".NET 8 OS compatibility test failed with exit code '{exitCode}' and output: {GetShortOutput(context, output)}" } ) ;
2024-08-02 14:37:46 -05:00
}
}
}
2024-08-07 16:53:00 -05:00
}
catch ( Exception ex )
{
Trace . Error ( "An error occurred while testing .NET 8 compatibility'" ) ;
Trace . Error ( ex ) ;
2024-08-13 09:02:26 -05:00
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(context, output)}'" } ) ;
2024-08-02 14:37:46 -05:00
}
}
2024-08-07 16:53:00 -05:00
2024-08-13 09:02:26 -05:00
private static string GetShortOutput ( IExecutionContext context , List < string > output )
2024-08-07 16:53:00 -05:00
{
2024-08-13 09:02:26 -05:00
var length = context . Global . Variables . System_DotNet8CompatibilityOutputLength ? ? 200 ;
2024-08-07 16:53:00 -05:00
var outputStr = string . Join ( "\n" , output ) . Trim ( ) ;
2024-08-13 09:02:26 -05:00
return outputStr . Length > length ? string . Concat ( outputStr . Substring ( 0 , length ) , "[...]" ) : outputStr ;
2024-08-07 16:53:00 -05:00
}
2024-08-02 14:37:46 -05:00
}
}