mirror of
https://github.com/actions/runner.git
synced 2025-12-26 03:17:32 +08:00
GitHub Actions Runner
This commit is contained in:
18
src/Runner.Common/Util/EnumUtil.cs
Normal file
18
src/Runner.Common/Util/EnumUtil.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
namespace GitHub.Runner.Common.Util
|
||||
{
|
||||
using System;
|
||||
|
||||
public static class EnumUtil
|
||||
{
|
||||
public static T? TryParse<T>(string value) where T: struct
|
||||
{
|
||||
T val;
|
||||
if (Enum.TryParse(value ?? string.Empty, ignoreCase: true, result: out val))
|
||||
{
|
||||
return val;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
28
src/Runner.Common/Util/PlanUtil.cs
Normal file
28
src/Runner.Common/Util/PlanUtil.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using GitHub.DistributedTask.WebApi;
|
||||
using GitHub.Runner.Sdk;
|
||||
|
||||
namespace GitHub.Runner.Common.Util
|
||||
{
|
||||
public static class PlanUtil
|
||||
{
|
||||
public static PlanFeatures GetFeatures(TaskOrchestrationPlanReference plan)
|
||||
{
|
||||
ArgUtil.NotNull(plan, nameof(plan));
|
||||
PlanFeatures features = PlanFeatures.None;
|
||||
if (plan.Version >= 8)
|
||||
{
|
||||
features |= PlanFeatures.JobCompletedPlanEvent;
|
||||
}
|
||||
|
||||
return features;
|
||||
}
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum PlanFeatures
|
||||
{
|
||||
None = 0,
|
||||
JobCompletedPlanEvent = 1,
|
||||
}
|
||||
}
|
||||
79
src/Runner.Common/Util/TaskResultUtil.cs
Normal file
79
src/Runner.Common/Util/TaskResultUtil.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
using GitHub.DistributedTask.WebApi;
|
||||
using System;
|
||||
|
||||
namespace GitHub.Runner.Common.Util
|
||||
{
|
||||
public static class TaskResultUtil
|
||||
{
|
||||
private static readonly int _returnCodeOffset = 100;
|
||||
|
||||
public static bool IsValidReturnCode(int returnCode)
|
||||
{
|
||||
int resultInt = returnCode - _returnCodeOffset;
|
||||
return Enum.IsDefined(typeof(TaskResult), resultInt);
|
||||
}
|
||||
|
||||
public static int TranslateToReturnCode(TaskResult result)
|
||||
{
|
||||
return _returnCodeOffset + (int)result;
|
||||
}
|
||||
|
||||
public static TaskResult TranslateFromReturnCode(int returnCode)
|
||||
{
|
||||
int resultInt = returnCode - _returnCodeOffset;
|
||||
if (Enum.IsDefined(typeof(TaskResult), resultInt))
|
||||
{
|
||||
return (TaskResult)resultInt;
|
||||
}
|
||||
else
|
||||
{
|
||||
return TaskResult.Failed;
|
||||
}
|
||||
}
|
||||
|
||||
// Merge 2 TaskResults get the worst result.
|
||||
// Succeeded -> Failed/Canceled/Skipped/Abandoned
|
||||
// Failed -> Failed/Canceled
|
||||
// Canceled -> Canceled
|
||||
// Skipped -> Skipped
|
||||
// Abandoned -> Abandoned
|
||||
public static TaskResult MergeTaskResults(TaskResult? currentResult, TaskResult comingResult)
|
||||
{
|
||||
if (currentResult == null)
|
||||
{
|
||||
return comingResult;
|
||||
}
|
||||
|
||||
// current result is Canceled/Skip/Abandoned
|
||||
if (currentResult > TaskResult.Failed)
|
||||
{
|
||||
return currentResult.Value;
|
||||
}
|
||||
|
||||
// comming result is bad than current result
|
||||
if (comingResult >= currentResult)
|
||||
{
|
||||
return comingResult;
|
||||
}
|
||||
|
||||
return currentResult.Value;
|
||||
}
|
||||
|
||||
public static ActionResult ToActionResult(this TaskResult result)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
case TaskResult.Succeeded:
|
||||
return ActionResult.Success;
|
||||
case TaskResult.Failed:
|
||||
return ActionResult.Failure;
|
||||
case TaskResult.Canceled:
|
||||
return ActionResult.Cancelled;
|
||||
case TaskResult.Skipped:
|
||||
return ActionResult.Skipped;
|
||||
default:
|
||||
throw new NotSupportedException(result.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
79
src/Runner.Common/Util/UnixUtil.cs
Normal file
79
src/Runner.Common/Util/UnixUtil.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using GitHub.Runner.Sdk;
|
||||
|
||||
namespace GitHub.Runner.Common.Util
|
||||
{
|
||||
[ServiceLocator(Default = typeof(UnixUtil))]
|
||||
public interface IUnixUtil : IRunnerService
|
||||
{
|
||||
Task ExecAsync(string workingDirectory, string toolName, string argLine);
|
||||
Task ChmodAsync(string mode, string file);
|
||||
Task ChownAsync(string owner, string group, string file);
|
||||
}
|
||||
|
||||
public sealed class UnixUtil : RunnerService, IUnixUtil
|
||||
{
|
||||
private ITerminal _term;
|
||||
|
||||
public override void Initialize(IHostContext hostContext)
|
||||
{
|
||||
base.Initialize(hostContext);
|
||||
_term = hostContext.GetService<ITerminal>();
|
||||
}
|
||||
|
||||
public async Task ChmodAsync(string mode, string file)
|
||||
{
|
||||
Trace.Entering();
|
||||
await ExecAsync(HostContext.GetDirectory(WellKnownDirectory.Root), "chmod", $"{mode} \"{file}\"");
|
||||
}
|
||||
|
||||
public async Task ChownAsync(string owner, string group, string file)
|
||||
{
|
||||
Trace.Entering();
|
||||
await ExecAsync(HostContext.GetDirectory(WellKnownDirectory.Root), "chown", $"{owner}:{group} \"{file}\"");
|
||||
}
|
||||
|
||||
public async Task ExecAsync(string workingDirectory, string toolName, string argLine)
|
||||
{
|
||||
Trace.Entering();
|
||||
|
||||
string toolPath = WhichUtil.Which(toolName, trace: Trace);
|
||||
Trace.Info($"Running {toolPath} {argLine}");
|
||||
|
||||
var processInvoker = HostContext.CreateService<IProcessInvoker>();
|
||||
processInvoker.OutputDataReceived += OnOutputDataReceived;
|
||||
processInvoker.ErrorDataReceived += OnErrorDataReceived;
|
||||
|
||||
try
|
||||
{
|
||||
using (var cs = new CancellationTokenSource(TimeSpan.FromSeconds(45)))
|
||||
{
|
||||
await processInvoker.ExecuteAsync(workingDirectory, toolPath, argLine, null, true, cs.Token);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
processInvoker.OutputDataReceived -= OnOutputDataReceived;
|
||||
processInvoker.ErrorDataReceived -= OnErrorDataReceived;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnOutputDataReceived(object sender, ProcessDataReceivedEventArgs e)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(e.Data))
|
||||
{
|
||||
_term.WriteLine(e.Data);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnErrorDataReceived(object sender, ProcessDataReceivedEventArgs e)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(e.Data))
|
||||
{
|
||||
_term.WriteLine(e.Data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
63
src/Runner.Common/Util/VarUtil.cs
Normal file
63
src/Runner.Common/Util/VarUtil.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using GitHub.Runner.Sdk;
|
||||
|
||||
namespace GitHub.Runner.Common.Util
|
||||
{
|
||||
public static class VarUtil
|
||||
{
|
||||
public static StringComparer EnvironmentVariableKeyComparer
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (Constants.Runner.Platform)
|
||||
{
|
||||
case Constants.OSPlatform.Linux:
|
||||
case Constants.OSPlatform.OSX:
|
||||
return StringComparer.Ordinal;
|
||||
case Constants.OSPlatform.Windows:
|
||||
return StringComparer.OrdinalIgnoreCase;
|
||||
default:
|
||||
throw new NotSupportedException(); // Should never reach here.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string OS
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (Constants.Runner.Platform)
|
||||
{
|
||||
case Constants.OSPlatform.Linux:
|
||||
return "Linux";
|
||||
case Constants.OSPlatform.OSX:
|
||||
return "macOS";
|
||||
case Constants.OSPlatform.Windows:
|
||||
return "Windows";
|
||||
default:
|
||||
throw new NotSupportedException(); // Should never reach here.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string OSArchitecture
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (Constants.Runner.PlatformArchitecture)
|
||||
{
|
||||
case Constants.Architecture.X86:
|
||||
return "X86";
|
||||
case Constants.Architecture.X64:
|
||||
return "X64";
|
||||
case Constants.Architecture.Arm:
|
||||
return "ARM";
|
||||
default:
|
||||
throw new NotSupportedException(); // Should never reach here.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user