diff --git a/src/Runner.Worker/ExecutionContext.cs b/src/Runner.Worker/ExecutionContext.cs index 3a3754fa7..6dd3c2adf 100644 --- a/src/Runner.Worker/ExecutionContext.cs +++ b/src/Runner.Worker/ExecutionContext.cs @@ -968,6 +968,9 @@ namespace GitHub.Runner.Worker // Verbosity (from GitHub.Step_Debug). Global.WriteDebug = Global.Variables.Step_Debug ?? false; + // Debugger enabled flag (from acquire response). + Global.EnableDebugger = message.EnableDebugger; + // Hook up JobServerQueueThrottling event, we will log warning on server tarpit. _jobServerQueue.JobServerQueueThrottling += JobServerQueueThrottling_EventReceived; } diff --git a/src/Runner.Worker/GlobalContext.cs b/src/Runner.Worker/GlobalContext.cs index 27c326d68..5ae7d4ae1 100644 --- a/src/Runner.Worker/GlobalContext.cs +++ b/src/Runner.Worker/GlobalContext.cs @@ -27,6 +27,7 @@ namespace GitHub.Runner.Worker public StepsContext StepsContext { get; set; } public Variables Variables { get; set; } public bool WriteDebug { get; set; } + public bool EnableDebugger { get; set; } public string InfrastructureFailureCategory { get; set; } public JObject ContainerHookState { get; set; } public bool HasTemplateEvaluatorMismatch { get; set; } diff --git a/src/Runner.Worker/JobRunner.cs b/src/Runner.Worker/JobRunner.cs index 72ee5a403..80f9caf6d 100644 --- a/src/Runner.Worker/JobRunner.cs +++ b/src/Runner.Worker/JobRunner.cs @@ -121,6 +121,11 @@ namespace GitHub.Runner.Worker jobContext.Start(); jobContext.Debug($"Starting: {message.JobDisplayName}"); + if (jobContext.Global.EnableDebugger) + { + Trace.Info("Debugger enabled for this job run"); + } + runnerShutdownRegistration = HostContext.RunnerShutdownToken.Register(() => { // log an issue, then runner get shutdown by Ctrl-C or Ctrl-Break. diff --git a/src/Sdk/DTPipelines/Pipelines/AgentJobRequestMessage.cs b/src/Sdk/DTPipelines/Pipelines/AgentJobRequestMessage.cs index e6ecbf450..328f62160 100644 --- a/src/Sdk/DTPipelines/Pipelines/AgentJobRequestMessage.cs +++ b/src/Sdk/DTPipelines/Pipelines/AgentJobRequestMessage.cs @@ -253,6 +253,13 @@ namespace GitHub.DistributedTask.Pipelines set; } + [DataMember(EmitDefaultValue = false)] + public bool EnableDebugger + { + get; + set; + } + /// /// Gets the collection of variables associated with the current context. /// diff --git a/src/Test/L0/Sdk/RSWebApi/AgentJobRequestMessageL0.cs b/src/Test/L0/Sdk/RSWebApi/AgentJobRequestMessageL0.cs new file mode 100644 index 000000000..33b30d308 --- /dev/null +++ b/src/Test/L0/Sdk/RSWebApi/AgentJobRequestMessageL0.cs @@ -0,0 +1,76 @@ +using System.Collections.Generic; +using System.IO; +using System.Runtime.Serialization.Json; +using System.Text; +using Xunit; +using GitHub.DistributedTask.Pipelines; + +namespace GitHub.Actions.RunService.WebApi.Tests; + +public sealed class AgentJobRequestMessageL0 +{ + [Fact] + [Trait("Level", "L0")] + [Trait("Category", "Common")] + public void VerifyEnableDebuggerDeserialization_WithTrue() + { + // Arrange + var serializer = new DataContractJsonSerializer(typeof(AgentJobRequestMessage)); + string jsonWithEnabledDebugger = DoubleQuotify("{'EnableDebugger': true}"); + + // Act + using var stream = new MemoryStream(); + stream.Write(Encoding.UTF8.GetBytes(jsonWithEnabledDebugger)); + stream.Position = 0; + var recoveredMessage = serializer.ReadObject(stream) as AgentJobRequestMessage; + + // Assert + Assert.NotNull(recoveredMessage); + Assert.True(recoveredMessage.EnableDebugger, "EnableDebugger should be true when JSON contains 'EnableDebugger': true"); + } + + [Fact] + [Trait("Level", "L0")] + [Trait("Category", "Common")] + public void VerifyEnableDebuggerDeserialization_DefaultToFalse() + { + // Arrange + var serializer = new DataContractJsonSerializer(typeof(AgentJobRequestMessage)); + string jsonWithoutDebugger = DoubleQuotify("{'messageType': 'PipelineAgentJobRequest'}"); + + // Act + using var stream = new MemoryStream(); + stream.Write(Encoding.UTF8.GetBytes(jsonWithoutDebugger)); + stream.Position = 0; + var recoveredMessage = serializer.ReadObject(stream) as AgentJobRequestMessage; + + // Assert + Assert.NotNull(recoveredMessage); + Assert.False(recoveredMessage.EnableDebugger, "EnableDebugger should default to false when JSON field is absent"); + } + + [Fact] + [Trait("Level", "L0")] + [Trait("Category", "Common")] + public void VerifyEnableDebuggerDeserialization_WithFalse() + { + // Arrange + var serializer = new DataContractJsonSerializer(typeof(AgentJobRequestMessage)); + string jsonWithDisabledDebugger = DoubleQuotify("{'EnableDebugger': false}"); + + // Act + using var stream = new MemoryStream(); + stream.Write(Encoding.UTF8.GetBytes(jsonWithDisabledDebugger)); + stream.Position = 0; + var recoveredMessage = serializer.ReadObject(stream) as AgentJobRequestMessage; + + // Assert + Assert.NotNull(recoveredMessage); + Assert.False(recoveredMessage.EnableDebugger, "EnableDebugger should be false when JSON contains 'EnableDebugger': false"); + } + + private static string DoubleQuotify(string text) + { + return text.Replace('\'', '"'); + } +}