Skip to content
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 Assets/Editor/CompileCheckWindow/CompileCheckerExample.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public static async void TestCompileChecker()

CompileResult result = await compileController.TryCompileAsync(
forceRecompile: false,
pausePointWarning: null,
ct: CancellationToken.None);
CompilerMessage[] err = result.Errors;
CompilerMessage[] warning = result.Warnings;
Expand Down Expand Up @@ -71,6 +72,7 @@ public static async void TestForceCompileChecker()
// Example of forced re-compilation
CompileResult result = await compileController.TryCompileAsync(
forceRecompile: true,
pausePointWarning: null,
ct: CancellationToken.None);
CompilerMessage[] err = result.Errors;
CompilerMessage[] warning = result.Warnings;
Expand Down
2 changes: 1 addition & 1 deletion Assets/Editor/CompileCheckWindow/CompileEditorWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ private async Task ExecuteCompileAsync()
return;
}

CompileResult result = await _compileController.TryCompileAsync(_forceRecompile, CancellationToken.None);
CompileResult result = await _compileController.TryCompileAsync(_forceRecompile, pausePointWarning: null, CancellationToken.None);
if (ShouldRunExecuteDynamicCodeReadinessAfterCompile(result))
{
_isPostCompileReadinessRunning = true;
Expand Down
49 changes: 49 additions & 0 deletions Assets/Tests/Editor/CompilePausePointWarningBuilderTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using NUnit.Framework;

using io.github.hatayama.UnityCliLoop.FirstPartyTools;

namespace io.github.hatayama.UnityCliLoop.Tests.Editor
{
/// <summary>
/// Verifies the compile Warning text only appears when Play Mode was active with at least
/// one enabled pause point, and states the domain-reload loss when it does.
/// </summary>
[TestFixture]
public sealed class CompilePausePointWarningBuilderTests
{
[Test]
public void BuildWarning_WhenNotPlayingAtRequestStart_ReturnsNull()
{
// Verifies no warning is produced when Play Mode was not active, regardless of marker count.
string warning = CompilePausePointWarningBuilder.BuildWarning(
wasPlayingAtRequestStart: false,
activePausePointCount: 3);

Assert.That(warning, Is.Null);
}

[Test]
public void BuildWarning_WhenPlayingButNoActivePausePoints_ReturnsNull()
{
// Verifies no warning is produced when Play Mode was active but no pause point is enabled.
string warning = CompilePausePointWarningBuilder.BuildWarning(
wasPlayingAtRequestStart: true,
activePausePointCount: 0);

Assert.That(warning, Is.Null);
}

[Test]
public void BuildWarning_WhenPlayingWithActivePausePoints_MentionsCountAndDomainReloadLoss()
{
// Verifies the warning names the active count and explains what the domain reload discards.
string warning = CompilePausePointWarningBuilder.BuildWarning(
wasPlayingAtRequestStart: true,
activePausePointCount: 2);

Assert.That(warning, Does.Contain("2 enabled pause point"));
Assert.That(warning, Does.Contain("Play session state"));
Assert.That(warning, Does.Contain("pause point patches"));
}
}
}
11 changes: 11 additions & 0 deletions Assets/Tests/Editor/CompilePausePointWarningBuilderTests.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 9 additions & 9 deletions Assets/Tests/Editor/CompileResponseFactoryTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public void CreateResponse_WhenNormalCompileCompletes_MapsDetailedIssues()
warnings: new[] { warning });

CompileResponse response =
CompileResponseFactory.CreateResponse(result, forceRecompile: false);
CompileResponseFactory.CreateResponse(result, forceRecompile: false, pausePointWarning: null);

Assert.That(response.Success, Is.False);
Assert.That(response.ErrorCount, Is.EqualTo(1));
Expand Down Expand Up @@ -75,7 +75,7 @@ public void CreateResponse_WhenForceCompileIsUnknown_ExplainsNullDetails()
message: null);

CompileResponse response =
CompileResponseFactory.CreateResponse(result, forceRecompile: true);
CompileResponseFactory.CreateResponse(result, forceRecompile: true, pausePointWarning: null);

Assert.That(response.Success, Is.False);
Assert.That(response.ErrorCount, Is.Null);
Expand All @@ -102,7 +102,7 @@ public void CreateResponse_WhenForceCompileHasOutcome_ExplainsNullDetails()
message: "Internal force compile status message.");

CompileResponse response =
CompileResponseFactory.CreateResponse(result, forceRecompile: true);
CompileResponseFactory.CreateResponse(result, forceRecompile: true, pausePointWarning: null);

Assert.That(response.Success, Is.False);
Assert.That(response.ErrorCount, Is.Null);
Expand Down Expand Up @@ -144,7 +144,7 @@ public void CreateResponse_WhenIndeterminateNonForceCompileHasCounts_PreservesCo
message: null);

CompileResponse response =
CompileResponseFactory.CreateResponse(result, forceRecompile: false);
CompileResponseFactory.CreateResponse(result, forceRecompile: false, pausePointWarning: null);

Assert.That(response.Success, Is.False);
Assert.That(response.ErrorCount, Is.EqualTo(1));
Expand Down Expand Up @@ -179,7 +179,7 @@ public void CreateResponse_WhenForceCompileHasPreservedFailure_MapsDetailedIssue
preserveDetailsWhenForceRecompile: true);

CompileResponse response =
CompileResponseFactory.CreateResponse(result, forceRecompile: true);
CompileResponseFactory.CreateResponse(result, forceRecompile: true, pausePointWarning: null);

Assert.That(response.Success, Is.False);
Assert.That(response.ErrorCount, Is.EqualTo(1));
Expand Down Expand Up @@ -210,7 +210,7 @@ public void CreateResponse_WhenExternalSceneCannotBeResolved_AddsNextActions()
message: error.message);

CompileResponse response =
CompileResponseFactory.CreateResponse(result, forceRecompile: false);
CompileResponseFactory.CreateResponse(result, forceRecompile: false, pausePointWarning: null);

Assert.That(response.NextActions, Is.Not.Null);
Assert.That(response.NextActions, Has.Length.EqualTo(2));
Expand Down Expand Up @@ -245,7 +245,7 @@ public void CreateResponse_WhenExternalSceneCannotBeReloaded_AddsNextActions()
message: error.message);

CompileResponse response =
CompileResponseFactory.CreateResponse(result, forceRecompile: false);
CompileResponseFactory.CreateResponse(result, forceRecompile: false, pausePointWarning: null);

Assert.That(response.NextActions, Is.Not.Null);
Assert.That(response.NextActions, Has.Length.EqualTo(2));
Expand Down Expand Up @@ -275,7 +275,7 @@ public void CreateResponse_WhenExternalSceneStopMessageUsesDifferentWording_Does
message: error.message);

CompileResponse response =
CompileResponseFactory.CreateResponse(result, forceRecompile: false);
CompileResponseFactory.CreateResponse(result, forceRecompile: false, pausePointWarning: null);

Assert.That(response.NextActions, Is.Null);
}
Expand All @@ -301,7 +301,7 @@ public void CreateResponse_WhenUnityTestFrameworkSymbolIsMissing_AddsTestAsmdefH
warnings: Array.Empty<CompilerMessage>());

CompileResponse response =
CompileResponseFactory.CreateResponse(result, forceRecompile: false);
CompileResponseFactory.CreateResponse(result, forceRecompile: false, pausePointWarning: null);

Assert.That(response.Message, Does.Contain("TestAssemblies"));
Assert.That(response.Message, Does.Contain("com.unity.test-framework"));
Expand Down
4 changes: 2 additions & 2 deletions Assets/Tests/Editor/CompileSessionResultStoreTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,9 @@ public void StoreCompileResult_WhenEquivalentNormalResponsesAreStoredTwice_Write
errors: Array.Empty<CompilerMessage>(),
warnings: new[] { warning });
CompileResponse firstResponse =
CompileResponseFactory.CreateResponse(result, forceRecompile: false);
CompileResponseFactory.CreateResponse(result, forceRecompile: false, pausePointWarning: null);
CompileResponse secondResponse =
CompileResponseFactory.CreateResponse(result, forceRecompile: false);
CompileResponseFactory.CreateResponse(result, forceRecompile: false, pausePointWarning: null);

CompileSessionResultStore.StoreCompileResult(
compileResultSessionRepository,
Expand Down
4 changes: 3 additions & 1 deletion Assets/Tests/Editor/CompileUseCaseTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public async Task CompileAsync_WhenExecutionLayerStoresDelayedSuccess_DoesNotSto
compileSessionLifecycleService,
compileResultSessionRepository,
pendingCompileSessionRepository);
useCase.SetCompilationExecutionForTesting((compileRequest, ct) =>
useCase.SetCompilationExecutionForTesting((compileRequest, pausePointWarning, ct) =>
{
ct.ThrowIfCancellationRequested();
CompileResultSessionRecorder.RecordCompileResult(
Expand All @@ -67,6 +67,8 @@ public async Task CompileAsync_WhenExecutionLayerStoresDelayedSuccess_DoesNotSto
Assert.That(compileResultSessionRepository.StoreCount, Is.EqualTo(1));
Assert.That(response.Success, Is.True);
Assert.That(response.ProjectRoot, Is.Not.Empty);
// Verifies no pause-point Warning appears outside Play Mode (the only state an EditMode test can exercise).
Assert.That(response.Warning, Is.Null);
UnityCliLoopStoredCompileResult storedResult =
compileResultSessionRepository.GetCompileResult("compile_test_request");
Assert.That(storedResult.ResultJson, Does.Contain("\"ProjectRoot\":"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ public CompilationExecutionService(
/// Execute compilation asynchronously
/// </summary>
/// <param name="request">Compile request with force and delayed-result settings.</param>
/// <param name="pausePointWarning">Optional Warning to carry onto the shaped response, e.g. when Play Mode was active with enabled pause points.</param>
/// <returns>Compilation result</returns>
public async Task<CompileResult> ExecuteCompilationAsync(CompileSchema request, CancellationToken ct)
public async Task<CompileResult> ExecuteCompilationAsync(CompileSchema request, string pausePointWarning, CancellationToken ct)
{
if (request == null)
{
Expand All @@ -47,7 +48,7 @@ public async Task<CompileResult> ExecuteCompilationAsync(CompileSchema request,
_pendingCompileSessionRepository);
compileController.SetResultRecordingContext(CompileResultRecordingContext.Create(request));
compileController.SetExternalSceneChangePolicy(request.ReloadExternalSceneChanges);
return await compileController.TryCompileAsync(request.ForceRecompile, ct).ConfigureAwait(false);
return await compileController.TryCompileAsync(request.ForceRecompile, pausePointWarning, ct).ConfigureAwait(false);
}
}
}
17 changes: 12 additions & 5 deletions Packages/src/Editor/FirstPartyTools/Compile/CompileController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class CompileController : IDisposable
private List<CompilerMessage> _compileMessages = new();
private TaskCompletionSource<CompileResult> _currentCompileTask;
private bool _isForceCompile = false;
private string _pendingPausePointWarning;
private bool _reloadExternalSceneChanges = true;
private CompileResultRecordingContext _resultRecordingContext = CompileResultRecordingContext.Disabled();
private DateTime _compileStartedAtUtc = DateTime.MinValue;
Expand Down Expand Up @@ -96,15 +97,18 @@ internal void SetExternalSceneChangePolicy(bool reloadExternalSceneChanges)
/// Executes compilation asynchronously.
/// </summary>
/// <param name="forceRecompile">Whether to force a recompile.</param>
/// <param name="pausePointWarning">Optional Warning to carry onto the shaped response, e.g. when Play Mode was active with enabled pause points.</param>
/// <param name="ct">Cancellation token for the compile execution.</param>
/// <returns>The compilation result.</returns>
/// <exception cref="InvalidOperationException">Thrown when the task is not found during compilation.</exception>
/// <remarks>
/// Callers must validate editor compilation state before invoking compile execution;
/// the production pipeline does this in CompileUseCase.
/// </remarks>
public async Task<CompileResult> TryCompileAsync(bool forceRecompile, CancellationToken ct)
public async Task<CompileResult> TryCompileAsync(bool forceRecompile, string pausePointWarning, CancellationToken ct)
{
_pendingPausePointWarning = pausePointWarning;

if (_isCompiling)
{
// If compilation is already in progress, wait for the current task.
Expand Down Expand Up @@ -136,7 +140,7 @@ public async Task<CompileResult> TryCompileAsync(bool forceRecompile, Cancellati
});
CompileResult result =
CompileResultFactory.CreateExternalSceneChangeFailureResult(sceneChangeResult);
RecordCompileResultIfNeeded(result);
RecordCompileResultIfNeeded(result, pausePointWarning: null);
return result;
}

Expand Down Expand Up @@ -321,7 +325,7 @@ private void CompleteCompileRequest(CompileResult result, bool unregisterEvents)
// Completion subscribers are outside this controller, so state cleanup cannot depend on them returning.
try
{
RecordCompileResultIfNeeded(result);
RecordCompileResultIfNeeded(result, _pendingPausePointWarning);

if (unregisterEvents)
{
Expand All @@ -341,13 +345,14 @@ private void CompleteCompileRequest(CompileResult result, bool unregisterEvents)
_isForceCompile = false;
_resultRecordingContext = CompileResultRecordingContext.Disabled();
_compileStartedAtUtc = DateTime.MinValue;
_pendingPausePointWarning = null;
}

task?.TrySetResult(result);
}
}

private void RecordCompileResultIfNeeded(CompileResult result)
private void RecordCompileResultIfNeeded(CompileResult result, string pausePointWarning)
{
UnityEngine.Debug.Assert(result != null, "result must not be null");

Expand All @@ -362,7 +367,8 @@ private void RecordCompileResultIfNeeded(CompileResult result)
_resultRecordingContext.RequestId,
_resultRecordingContext.ForceRecompile,
result,
_resultRecordingContext.RequestId);
_resultRecordingContext.RequestId,
pausePointWarning);
}

/// <summary>
Expand Down Expand Up @@ -462,6 +468,7 @@ public void Cleanup()
_reloadExternalSceneChanges = true;
_resultRecordingContext = CompileResultRecordingContext.Disabled();
_compileStartedAtUtc = DateTime.MinValue;
_pendingPausePointWarning = null;
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace io.github.hatayama.UnityCliLoop.FirstPartyTools
{
/// <summary>
/// Builds the compile Warning text for the case where Play Mode was active with enabled
/// pause points at the moment compile was requested: the domain reload that follows discards
/// both the Play session state and every pause-point Harmony patch.
/// </summary>
internal static class CompilePausePointWarningBuilder
{
public static string BuildWarning(bool wasPlayingAtRequestStart, int activePausePointCount)
{
if (!wasPlayingAtRequestStart || activePausePointCount <= 0)
{
return null;
}

return "Play Mode was active with " + activePausePointCount + " enabled pause point(s). "
+ "The compile stops Play Mode and the domain reload discards the Play session state "
+ "and all pause point patches — re-enable pause points after the compile completes.";
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ public class CompileResponse : UnityCliLoopToolResponse
/// </summary>
public string ProjectRoot { get; set; }

/// <summary>
/// Optional warning about a condition compile does not block on, e.g. Play Mode being
/// active with enabled pause points whose patches the domain reload will discard.
/// </summary>
public string Warning { get; set; }

/// <summary>
/// Create a new CompileResponse
/// </summary>
Expand Down
Loading