Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
88a3519
Add V3 custom tool migration to setup wizard
hatayama May 12, 2026
672a4bd
Preserve supported V2 tool metadata during migration
hatayama May 13, 2026
18e0373
Tighten V3 migration target detection
hatayama May 13, 2026
08c356d
Keep manual registration migrations compilable
hatayama May 13, 2026
254f317
Handle bracketed descriptions in migration attributes
hatayama May 13, 2026
f35ecff
Add Domain references for migrated registrar metadata
hatayama May 13, 2026
2ee4b0d
Migrate split files that rely on legacy global usings
hatayama May 13, 2026
ac018fa
Track split registrar usage in migrated assemblies
hatayama May 13, 2026
e40602b
Handle implicit assemblies and sidecars in migration
hatayama May 13, 2026
fd59ede
Handle aliased legacy registrar references
hatayama May 13, 2026
d4f513e
Separate implicit assemblies during migration
hatayama May 13, 2026
c3123ae
Migrate global attributes and metadata helpers
hatayama May 13, 2026
23ef3cc
Resolve asmref assemblies during tool migration
hatayama May 13, 2026
69805b0
Preserve interpolation code during migration
hatayama May 13, 2026
f34c28c
Handle assembly-scoped migration edge cases
hatayama May 13, 2026
6d71a8c
Exclude package folders from tool migration
hatayama May 13, 2026
f0a87e8
Handle raw interpolated strings during migration
hatayama May 13, 2026
1ea32f6
Restrict contract type migration to legacy qualifiers
hatayama May 13, 2026
05062f0
Gate bare tool attribute migration on legacy context
hatayama May 13, 2026
73fd9a1
Migrate split bare tool attributes in legacy assemblies
hatayama May 13, 2026
c5e12b6
Tighten legacy migration marker matching
hatayama May 13, 2026
6cf8182
Handle legacy ToolInfo constructor migration
hatayama May 13, 2026
ddab268
Preserve ToolInfo development flag migration
hatayama May 13, 2026
062224d
Tighten third-party migration scope detection
hatayama May 13, 2026
619799d
Respect Unity migration scan boundaries
hatayama May 13, 2026
d73a9d3
Limit migration inventory to Assets
hatayama May 13, 2026
c8746e6
Propagate global legacy aliases during migration
hatayama May 13, 2026
0a879ec
Constrain ToolInfo constructor migration to legacy forms
hatayama May 13, 2026
e7729c9
Preserve current registrar assembly references
hatayama May 13, 2026
47eeec4
Preserve legacy using alias identifiers
hatayama May 13, 2026
b5ca2e4
Preserve current registrar asmdef references
hatayama May 13, 2026
4d88650
Migrate aliased ToolInfo constructors first
hatayama May 13, 2026
ec82000
Handle global alias migration edge cases
hatayama May 13, 2026
8374839
Constrain ToolInfo migration contexts
hatayama May 13, 2026
a22a307
Preserve contract member identifiers
hatayama May 13, 2026
8d31d72
Migrate unambiguous ToolInfo constructors
hatayama May 13, 2026
f8bd1d7
Migrate stale ToolContracts asmdef GUIDs
hatayama May 13, 2026
ab0e70c
Cover partial migration edge cases
hatayama May 13, 2026
98457d8
Preserve registrar and security aliases during migration
hatayama May 13, 2026
a837ed7
Handle asmdefs without references during migration
hatayama May 13, 2026
3aedcd7
Highlight setup wizard migration action
hatayama May 14, 2026
9c59e3a
Explain setup wizard migration prompt
hatayama May 14, 2026
0aec8b5
Migrate legacy Domain helper references
hatayama May 14, 2026
2f7d4cb
Avoid duplicate current asmdef references
hatayama May 14, 2026
78bfb5b
Migrate legacy constants references
hatayama May 14, 2026
fdb4f0f
Handle remaining migration dependency edge cases
hatayama May 14, 2026
a26e2dd
Avoid registrar false positives in migration scans
hatayama May 14, 2026
631c15e
Soften setup migration alert color
hatayama May 14, 2026
cd40d1b
Thicken setup migration alert border
hatayama May 14, 2026
ae5a688
Add incremental setup migration preview
hatayama May 14, 2026
c76fb53
Avoid current asmdef migration false positives
hatayama May 14, 2026
08b2a77
Avoid setup wizard migration scans on manual open
hatayama May 14, 2026
90e6306
Split custom tool migration into its own wizard
hatayama May 14, 2026
732ac49
Add migration wizard reopen hint
hatayama May 14, 2026
ed62fa6
Match migration wizard warning colors
hatayama May 14, 2026
972fc96
Reduce migration alert border thickness
hatayama May 14, 2026
7c552ac
Fit migration wizard to content size
hatayama May 14, 2026
40d9579
Keep migration wizard at setup width
hatayama May 14, 2026
d090996
Clarify migration wizard empty state
hatayama May 14, 2026
8c210f1
Refresh async migration previews from disk
hatayama May 14, 2026
a8c7cf5
Detect partial asmdef migrations on startup
hatayama May 14, 2026
dbed64d
Avoid unrelated asmdef parsing in startup scan
hatayama May 14, 2026
e004b93
Keep asmdef repair scans scoped to relevant assemblies
hatayama May 14, 2026
fe4f48d
Add Domain refs for registrar return migrations
hatayama May 14, 2026
f9ab656
Fix legacy metadata constructor migrations
hatayama May 14, 2026
05be99e
Keep ToolInfo aliases scoped to constructors
hatayama May 14, 2026
6d6cb91
Address migration wizard review findings
hatayama May 14, 2026
a453b3a
Skip unreadable migration assembly JSON
hatayama May 14, 2026
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
11 changes: 11 additions & 0 deletions Assets/Tests/Editor/OnionAssemblyDependencyTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -851,6 +851,17 @@ public void SetupWizardStartup_WhenLoaded_SchedulesVersionCheckInsteadOfReadingS
Assert.That(setupWizardSource, Does.Not.Contain("\n TryShowOnVersionChange();"));
}

[Test]
public void MigrationWizardStartup_WhenLoaded_SchedulesTargetCheckInsteadOfPreviewingSynchronously()
{
// Tests that migration target detection does not block the synchronous Editor startup hook.
string migrationWizardSource = ReadProductionSource(
"Packages/src/Editor/Presentation/Setup/ThirdPartyToolMigrationWizardWindow.cs");

Assert.That(migrationWizardSource, Does.Contain("EditorApplication.delayCall += TryShowOnMigrationTargets;"));
Assert.That(migrationWizardSource, Does.Not.Contain("\n TryShowOnMigrationTargets();"));
}

[Test]
public void ProjectAsmdefs_WhenLoaded_DoNotReferenceRemovedSharedAssemblyGuid()
{
Expand Down
5 changes: 4 additions & 1 deletion Assets/Tests/Editor/SetupWizardWindowTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,10 @@ public void ShouldAutoShowForVersion_ReturnsExpectedValue(
bool expected)
{
bool shouldAutoShow =
SetupWizardWindow.ShouldAutoShowForVersion(currentVersion, lastSeenVersion, suppressAutoShow);
SetupWizardWindow.ShouldAutoShowForVersion(
currentVersion,
lastSeenVersion,
suppressAutoShow);

Assert.That(shouldAutoShow, Is.EqualTo(expected));
}
Expand Down
2,375 changes: 2,375 additions & 0 deletions Assets/Tests/Editor/ThirdPartyToolMigrationFileServiceTests.cs

Large diffs are not rendered by default.

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

1,494 changes: 1,494 additions & 0 deletions Assets/Tests/Editor/ThirdPartyToolMigrationRulesTests.cs

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions Assets/Tests/Editor/ThirdPartyToolMigrationRulesTests.cs.meta

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

151 changes: 151 additions & 0 deletions Assets/Tests/Editor/ThirdPartyToolMigrationWizardWindowTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
using NUnit.Framework;
using UnityEditor;
using UnityEngine;

using io.github.hatayama.UnityCliLoop.Domain;
using io.github.hatayama.UnityCliLoop.Presentation;

namespace io.github.hatayama.UnityCliLoop.Tests.Editor
{
/// <summary>
/// Test fixture that verifies the dedicated V3 custom tool migration wizard.
/// </summary>
public sealed class ThirdPartyToolMigrationWizardWindowTests
{
[TestCase(true, true)]
[TestCase(false, false)]
public void ShouldAutoShowForMigrationTargets_ReturnsDetectionResult(
bool hasMigrationTargets,
bool expected)
{
// Verifies that migration startup is controlled only by migration target detection.
bool shouldAutoShow =
ThirdPartyToolMigrationWizardWindow.ShouldAutoShowForMigrationTargets(hasMigrationTargets);

Assert.That(shouldAutoShow, Is.EqualTo(expected));
}

[TestCase(
1,
"1 file needs V3 custom tool migration.\n" +
"The Unity Console is showing errors because this file still uses the old custom tool API.\n\n" +
"Click Migrate to update it automatically. The errors should disappear after migration.")]
[TestCase(
3,
"3 files need V3 custom tool migration.\n" +
"The Unity Console is showing errors because these files still use the old custom tool API.\n\n" +
"Click Migrate to update them automatically. The errors should disappear after migration.")]
public void GetMigrationStatusText_WhenTargetsExist_ReturnsFileCount(
int fileCount,
string expectedText)
{
// Verifies that the migration wizard summarizes detected V2 custom tool files.
string text = ThirdPartyToolMigrationWizardWindow.GetMigrationStatusText(fileCount);

Assert.That(text, Is.EqualTo(expectedText));
}

[Test]
public void GetMigrationProgressText_WhenProgressExists_ReturnsCheckCount()
{
// Verifies that the migration wizard reports scan progress while migration targets are unknown.
ThirdPartyToolMigrationProgress progress = new(3, 12);

string text = ThirdPartyToolMigrationWizardWindow.GetMigrationProgressText(progress);

Assert.That(
text,
Is.EqualTo("Scanning project for V3 custom tool migration...\n3/12 checks complete."));
}

[TestCase(false, true, "Migrate")]
[TestCase(true, true, "Migrating...")]
[TestCase(false, false, "Nothing to migrate")]
public void GetMigrationButtonText_ReturnsExpectedLabel(
bool isMigrating,
bool hasMigrationTargets,
string expectedLabel)
{
// Verifies that the migration action communicates its current state.
string label = ThirdPartyToolMigrationWizardWindow.GetMigrationButtonText(
isMigrating,
hasMigrationTargets);

Assert.That(label, Is.EqualTo(expectedLabel));
}

[Test]
public void PrepareForOpen_PopulatesWindowStateBeforeShowing()
{
// Verifies that startup-created migration windows can preview immediately after CreateGUI.
ThirdPartyToolMigrationWizardWindow window =
ScriptableObject.CreateInstance<ThirdPartyToolMigrationWizardWindow>();
try
{
Rect position = new(12f, 34f, 360f, 220f);

ThirdPartyToolMigrationWizardWindow.PrepareForOpen(
window,
"Unity CLI Loop Migration",
position,
true);

SerializedObject serializedWindow = new(window);
SerializedProperty refreshProperty =
serializedWindow.FindProperty("_shouldRefreshAfterCreateGui");

Assert.That(window.titleContent.text, Is.EqualTo("Unity CLI Loop Migration"));
Assert.That(window.position, Is.EqualTo(position));
Assert.That(window.minSize, Is.EqualTo(new Vector2(360f, 120f)));
Assert.That(refreshProperty, Is.Not.Null);
Assert.That(refreshProperty.boolValue, Is.True);
}
finally
{
Object.DestroyImmediate(window);
}
}

[Test]
public void WithContentHeight_UsesMeasuredHeightAndPreservesCenter()
{
// Verifies that the migration wizard resizes vertically from measured content height.
Rect initialRect = new(123f, 456f, 400f, 220f);
Vector2 frameSize = new(18f, 28f);

Rect resizedRect =
ThirdPartyToolMigrationWizardWindow.WithContentHeight(initialRect, 180f, frameSize);

Assert.That(resizedRect.center, Is.EqualTo(initialRect.center));
Assert.That(resizedRect.size, Is.EqualTo(new Vector2(360f, 208f)));
}

[Test]
public void WithContentHeight_WhenMeasuredHeightIsSmall_ClampsToMinimumHeight()
{
// Verifies that content fitting keeps the migration wizard from becoming unusably short.
Rect initialRect = new(123f, 456f, 400f, 220f);
Vector2 frameSize = new(18f, 28f);

Rect resizedRect =
ThirdPartyToolMigrationWizardWindow.WithContentHeight(initialRect, 12f, frameSize);

Assert.That(resizedRect.center, Is.EqualTo(initialRect.center));
Assert.That(resizedRect.size, Is.EqualTo(new Vector2(360f, 120f)));
}

[Test]
public void WithContentHeight_WhenCurrentWidthIsWide_UsesSetupWizardWidth()
{
// Verifies that content fitting keeps the migration wizard at Setup Wizard width.
Rect initialRect = new(123f, 456f, 520f, 220f);
Vector2 frameSize = new(18f, 28f);

Rect resizedRect =
ThirdPartyToolMigrationWizardWindow.WithContentHeight(initialRect, 120f, frameSize);

Assert.That(resizedRect.center, Is.EqualTo(initialRect.center));
Assert.That(resizedRect.size, Is.EqualTo(new Vector2(360f, 148f)));
}
}
}

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
@@ -0,0 +1,56 @@
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;

using io.github.hatayama.UnityCliLoop.Domain;

namespace io.github.hatayama.UnityCliLoop.Application
{
/// <summary>
/// Coordinates V3 migration for third-party custom tools without owning file-system details.
/// </summary>
public sealed class ThirdPartyToolMigrationUseCase
{
private readonly IThirdPartyToolMigrationPort _migrationPort;

public ThirdPartyToolMigrationUseCase(IThirdPartyToolMigrationPort migrationPort)
{
Debug.Assert(migrationPort != null, "migrationPort must not be null");

_migrationPort = migrationPort ?? throw new ArgumentNullException(nameof(migrationPort));
}

public ThirdPartyToolMigrationPreview PreviewMigration(string projectRoot)
{
Debug.Assert(!string.IsNullOrEmpty(projectRoot), "projectRoot must not be null or empty");

return _migrationPort.PreviewMigration(projectRoot);
}

public Task<ThirdPartyToolMigrationPreview> PreviewMigrationAsync(
string projectRoot,
IProgress<ThirdPartyToolMigrationProgress> progress,
CancellationToken ct)
{
Debug.Assert(!string.IsNullOrEmpty(projectRoot), "projectRoot must not be null or empty");
Debug.Assert(progress != null, "progress must not be null");

return _migrationPort.PreviewMigrationAsync(projectRoot, progress, ct);
}

public Task<bool> HasMigrationTargetsAsync(string projectRoot, CancellationToken ct)
{
Debug.Assert(!string.IsNullOrEmpty(projectRoot), "projectRoot must not be null or empty");

return _migrationPort.HasMigrationTargetsAsync(projectRoot, ct);
}

public ThirdPartyToolMigrationResult ApplyMigration(string projectRoot)
{
Debug.Assert(!string.IsNullOrEmpty(projectRoot), "projectRoot must not be null or empty");

return _migrationPort.ApplyMigration(projectRoot);
}
}
}

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
@@ -0,0 +1,30 @@
using System;
using System.Diagnostics;

namespace io.github.hatayama.UnityCliLoop.Application
{
/// <summary>
/// Stores the third-party tool migration use case for Unity-created presentation objects.
/// </summary>
internal static class ThirdPartyToolMigrationUseCaseRegistry
{
private static ThirdPartyToolMigrationUseCase RegisteredUseCase;

internal static void Register(ThirdPartyToolMigrationUseCase useCase)
{
Debug.Assert(useCase != null, "useCase must not be null");

RegisteredUseCase = useCase ?? throw new ArgumentNullException(nameof(useCase));
}

internal static ThirdPartyToolMigrationUseCase GetRegisteredUseCase()
{
if (RegisteredUseCase == null)
{
throw new InvalidOperationException("Unity CLI Loop third-party tool migration use case is not registered.");
}

return RegisteredUseCase;
}
}
}

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 @@ -32,6 +32,8 @@ internal UnityCliLoopApplicationServices Register()
toolRegistrarService));
SkillSetupUseCase skillSetupUseCase = new(new SkillSetupService(new ToolSkillSetupService(toolSettingsService)));
SkillSetupUseCaseRegistry.Register(skillSetupUseCase);
ThirdPartyToolMigrationUseCaseRegistry.Register(
new ThirdPartyToolMigrationUseCase(new ThirdPartyToolMigrationFileService()));
CliSetupApplicationFacade.RegisterService(new CliSetupApplicationService(
new CliInstallationDetector(),
new NativeCliInstallerService()));
Expand Down
Loading