mirror of
https://github.com/actions/runner.git
synced 2026-01-23 04:51:23 +08:00
editing jobs
This commit is contained in:
@@ -13,6 +13,7 @@ using GitHub.DistributedTask.WebApi;
|
||||
using GitHub.Runner.Common;
|
||||
using GitHub.Runner.Common.Util;
|
||||
using GitHub.Runner.Sdk;
|
||||
using GitHub.Runner.Worker.Dap.StepCommands;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace GitHub.Runner.Worker.Dap
|
||||
@@ -282,9 +283,21 @@ namespace GitHub.Runner.Worker.Dap
|
||||
private readonly List<CompletedStepInfo> _completedSteps = new List<CompletedStepInfo>();
|
||||
private int _nextCompletedFrameId = CompletedFrameIdBase;
|
||||
|
||||
// Track completed IStep objects for the step manipulator
|
||||
private readonly List<IStep> _completedStepsTracker = new List<IStep>();
|
||||
|
||||
// Variable provider for converting contexts to DAP variables
|
||||
private DapVariableProvider _variableProvider;
|
||||
|
||||
// Step command parser for !step REPL commands
|
||||
private IStepCommandParser _stepCommandParser;
|
||||
|
||||
// Step command handler for executing step commands
|
||||
private IStepCommandHandler _stepCommandHandler;
|
||||
|
||||
// Step manipulator for queue operations
|
||||
private IStepManipulator _stepManipulator;
|
||||
|
||||
// Checkpoint storage for step-back (time-travel) debugging
|
||||
private readonly List<StepCheckpoint> _checkpoints = new List<StepCheckpoint>();
|
||||
private const int MaxCheckpoints = 50;
|
||||
@@ -319,6 +332,9 @@ namespace GitHub.Runner.Worker.Dap
|
||||
{
|
||||
base.Initialize(hostContext);
|
||||
_variableProvider = new DapVariableProvider(hostContext);
|
||||
_stepCommandParser = hostContext.GetService<IStepCommandParser>();
|
||||
_stepCommandHandler = hostContext.GetService<IStepCommandHandler>();
|
||||
_stepManipulator = hostContext.GetService<IStepManipulator>();
|
||||
Trace.Info("DapDebugSession initialized");
|
||||
}
|
||||
|
||||
@@ -661,6 +677,12 @@ namespace GitHub.Runner.Worker.Dap
|
||||
return HandleDebugCommand(expression);
|
||||
}
|
||||
|
||||
// Check for !step command (step manipulation commands)
|
||||
if (_stepCommandParser.IsStepCommand(expression))
|
||||
{
|
||||
return await HandleStepCommandAsync(expression);
|
||||
}
|
||||
|
||||
// Get the current execution context
|
||||
var executionContext = _currentStep?.ExecutionContext ?? _jobContext;
|
||||
if (executionContext == null)
|
||||
@@ -1096,6 +1118,81 @@ namespace GitHub.Runner.Worker.Dap
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles step manipulation commands (!step ...).
|
||||
/// Parses and executes commands using the StepCommandHandler.
|
||||
/// </summary>
|
||||
private async Task<Response> HandleStepCommandAsync(string expression)
|
||||
{
|
||||
Trace.Info($"Handling step command: {expression}");
|
||||
|
||||
try
|
||||
{
|
||||
var command = _stepCommandParser.Parse(expression);
|
||||
|
||||
// Ensure manipulator is initialized with current context
|
||||
EnsureManipulatorInitialized();
|
||||
|
||||
// Execute the command
|
||||
var result = await _stepCommandHandler.HandleAsync(command, _jobContext);
|
||||
|
||||
if (result.Success)
|
||||
{
|
||||
// Return appropriate response format based on input type
|
||||
if (command.WasJsonInput)
|
||||
{
|
||||
return CreateSuccessResponse(new EvaluateResponseBody
|
||||
{
|
||||
Result = Newtonsoft.Json.JsonConvert.SerializeObject(result),
|
||||
Type = "json",
|
||||
VariablesReference = 0
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
return CreateSuccessResponse(new EvaluateResponseBody
|
||||
{
|
||||
Result = result.Message,
|
||||
Type = "string",
|
||||
VariablesReference = 0
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return CreateErrorResponse($"[{result.Error}] {result.Message}");
|
||||
}
|
||||
}
|
||||
catch (StepCommandException ex)
|
||||
{
|
||||
Trace.Warning($"Step command error: {ex.ErrorCode} - {ex.Message}");
|
||||
|
||||
return CreateErrorResponse($"[{ex.ErrorCode}] {ex.Message}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Trace.Error($"Step command failed: {ex}");
|
||||
|
||||
return CreateErrorResponse($"Step command failed: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures the step manipulator is initialized with the current job context.
|
||||
/// </summary>
|
||||
private void EnsureManipulatorInitialized()
|
||||
{
|
||||
if (_jobContext == null)
|
||||
{
|
||||
throw new StepCommandException(StepCommandErrors.NoContext,
|
||||
"No job context available. Wait for the first step to start.");
|
||||
}
|
||||
|
||||
// The manipulator should already be initialized from OnStepStartingAsync
|
||||
// but just ensure the handler has the reference
|
||||
_stepCommandHandler.SetManipulator(_stepManipulator);
|
||||
}
|
||||
|
||||
private Response HandleSetBreakpoints(Request request)
|
||||
{
|
||||
// Stub - breakpoints not implemented in demo
|
||||
@@ -1187,6 +1284,9 @@ namespace GitHub.Runner.Worker.Dap
|
||||
_jobContext = jobContext;
|
||||
_jobCancellationToken = cancellationToken; // Store for REPL commands
|
||||
|
||||
// Initialize or update the step manipulator
|
||||
InitializeStepManipulator(step, isFirstStep);
|
||||
|
||||
// Hook up StepsContext debug logging (do this once when we first get jobContext)
|
||||
if (jobContext.Global.StepsContext.OnDebugLog == null)
|
||||
{
|
||||
@@ -1233,6 +1333,28 @@ namespace GitHub.Runner.Worker.Dap
|
||||
await WaitForCommandAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes or updates the step manipulator with the current state.
|
||||
/// </summary>
|
||||
private void InitializeStepManipulator(IStep currentStep, bool isFirstStep)
|
||||
{
|
||||
if (isFirstStep)
|
||||
{
|
||||
// First step - initialize fresh
|
||||
_stepManipulator.Initialize(_jobContext, 0);
|
||||
(_stepManipulator as StepManipulator)?.SetCurrentStep(currentStep);
|
||||
_stepCommandHandler.SetManipulator(_stepManipulator);
|
||||
_stepManipulator.RecordOriginalState();
|
||||
Trace.Info("Step manipulator initialized for debug session");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update current step reference
|
||||
(_stepManipulator as StepManipulator)?.SetCurrentStep(currentStep);
|
||||
_stepManipulator.UpdateCurrentIndex(_completedStepsTracker.Count + 1);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnStepCompleted(IStep step)
|
||||
{
|
||||
if (!IsActive)
|
||||
@@ -1269,6 +1391,10 @@ namespace GitHub.Runner.Worker.Dap
|
||||
FrameId = _nextCompletedFrameId++
|
||||
});
|
||||
|
||||
// Track IStep for the step manipulator
|
||||
_completedStepsTracker.Add(step);
|
||||
_stepManipulator?.AddCompletedStep(step);
|
||||
|
||||
// Clear current step reference since it's done
|
||||
// (will be set again when next step starts)
|
||||
}
|
||||
@@ -1604,6 +1730,16 @@ namespace GitHub.Runner.Worker.Dap
|
||||
_completedSteps.RemoveAt(_completedSteps.Count - 1);
|
||||
}
|
||||
|
||||
// Also clear the step tracker for manipulator sync
|
||||
while (_completedStepsTracker.Count > checkpointIndex)
|
||||
{
|
||||
_completedStepsTracker.RemoveAt(_completedStepsTracker.Count - 1);
|
||||
}
|
||||
|
||||
// Reset the step manipulator to match the restored state
|
||||
// It will be re-initialized when the restored step starts
|
||||
_stepManipulator?.ClearChanges();
|
||||
|
||||
// Store restored checkpoint for StepsRunner to consume
|
||||
_restoredCheckpoint = checkpoint;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user