Skip to content

Commit 12a238a

Browse files
committed
RequireCommit
1 parent 68ba8f5 commit 12a238a

File tree

2 files changed

+35
-95
lines changed

2 files changed

+35
-95
lines changed

src/Features/Core/Portable/ExternalAccess/Watch/Api/WatchHotReloadService.cs

Lines changed: 15 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -69,53 +69,6 @@ public readonly struct RunningProjectInfo
6969
public required bool RestartWhenChangesHaveNoEffect { get; init; }
7070
}
7171

72-
[Obsolete("Use Updates2")]
73-
public readonly struct Updates(
74-
ModuleUpdateStatus status,
75-
ImmutableArray<Diagnostic> diagnostics,
76-
ImmutableArray<Update> projectUpdates,
77-
IReadOnlySet<Project> projectsToRestart,
78-
IReadOnlySet<Project> projectsToRebuild)
79-
{
80-
/// <summary>
81-
/// Status of the updates.
82-
/// </summary>
83-
public readonly ModuleUpdateStatus Status { get; } = status;
84-
85-
/// <summary>
86-
/// Hot Reload specific diagnostics to be reported (includes rude edits and emit errors).
87-
/// </summary>
88-
public ImmutableArray<Diagnostic> Diagnostics { get; } = diagnostics;
89-
90-
/// <summary>
91-
/// Updates to be applied to modules. Empty if there are blocking rude edits.
92-
/// Only updates to projects that are not included in <see cref="ProjectsToRebuild"/> are listed.
93-
/// </summary>
94-
public ImmutableArray<Update> ProjectUpdates { get; } = projectUpdates;
95-
96-
/// <summary>
97-
/// Running projects that need to be restarted due to rude edits in order to apply changes.
98-
/// </summary>
99-
[Obsolete("Use ProjectIdsToRestart")]
100-
public IReadOnlySet<Project> ProjectsToRestart { get; } = projectsToRestart;
101-
102-
/// <summary>
103-
/// Projects with changes that need to be rebuilt in order to apply changes.
104-
/// </summary>
105-
[Obsolete("Use ProjectIdsToRebuild")]
106-
public IReadOnlySet<Project> ProjectsToRebuild { get; } = projectsToRebuild;
107-
108-
/// <summary>
109-
/// Running projects that need to be restarted due to rude edits in order to apply changes.
110-
/// </summary>
111-
public ImmutableArray<ProjectId> ProjectIdsToRestart { get; } = projectsToRestart.SelectAsArray(p => p.Id);
112-
113-
/// <summary>
114-
/// Projects with changes that need to be rebuilt in order to apply changes.
115-
/// </summary>
116-
public ImmutableArray<ProjectId> ProjectIdsToRebuild { get; } = projectsToRebuild.SelectAsArray(p => p.Id);
117-
}
118-
11972
public enum Status
12073
{
12174
/// <summary>
@@ -233,48 +186,8 @@ public void CapabilitiesChanged()
233186
public static string? GetTargetFramework(Project project)
234187
=> project.State.NameAndFlavor.flavor;
235188

236-
[Obsolete]
237-
public async Task<Updates> GetUpdatesAsync(Solution solution, IImmutableSet<ProjectId> runningProjects, CancellationToken cancellationToken)
238-
{
239-
var sessionId = GetDebuggingSession();
240-
241-
var runningProjectsImpl = runningProjects.ToImmutableDictionary(keySelector: p => p, elementSelector: _ => new EditAndContinue.RunningProjectInfo()
242-
{
243-
RestartWhenChangesHaveNoEffect = false,
244-
AllowPartialUpdate = true
245-
});
246-
247-
var results = await _encService.EmitSolutionUpdateAsync(sessionId, solution, runningProjectsImpl, s_solutionActiveStatementSpanProvider, cancellationToken).ConfigureAwait(false);
248-
249-
// If the changes fail to apply dotnet-watch fails.
250-
// We don't support discarding the changes and letting the user retry.
251-
if (!results.ModuleUpdates.Updates.IsEmpty)
252-
{
253-
_encService.CommitSolutionUpdate(sessionId);
254-
}
255-
256-
var diagnostics = results.GetAllDiagnostics();
257-
258-
var projectUpdates =
259-
from update in results.ModuleUpdates.Updates
260-
let project = solution.GetRequiredProject(update.ProjectId)
261-
where !results.ProjectsToRestart.ContainsKey(project.Id)
262-
select new Update(
263-
update.Module,
264-
project.Id,
265-
update.ILDelta,
266-
update.MetadataDelta,
267-
update.PdbDelta,
268-
update.UpdatedTypes,
269-
update.RequiredCapabilities);
270-
271-
return new Updates(
272-
results.ModuleUpdates.Status,
273-
diagnostics,
274-
[.. projectUpdates],
275-
results.ProjectsToRestart.Keys.Select(solution.GetRequiredProject).ToImmutableHashSet(),
276-
results.ProjectsToRebuild.Select(solution.GetRequiredProject).ToImmutableHashSet());
277-
}
189+
// TODO: remove, for backwards compat only
190+
public static bool RequireCommit { get; set; }
278191

279192
/// <summary>
280193
/// Emits updates for all projects that differ between the given <paramref name="solution"/> snapshot and the one given to the previous successful call or
@@ -303,7 +216,7 @@ public async Task<Updates2> GetUpdatesAsync(Solution solution, ImmutableDictiona
303216

304217
// If the changes fail to apply dotnet-watch fails.
305218
// We don't support discarding the changes and letting the user retry.
306-
if (!results.ModuleUpdates.Updates.IsEmpty)
219+
if (!RequireCommit && results.ModuleUpdates.Status is ModuleUpdateStatus.Ready or ModuleUpdateStatus.RestartRequired)
307220
{
308221
_encService.CommitSolutionUpdate(sessionId);
309222
}
@@ -332,6 +245,18 @@ public async Task<Updates2> GetUpdatesAsync(Solution solution, ImmutableDictiona
332245
};
333246
}
334247

248+
public void CommitUpdate()
249+
{
250+
var sessionId = GetDebuggingSession();
251+
_encService.CommitSolutionUpdate(sessionId);
252+
}
253+
254+
public void DiscardUpdate()
255+
{
256+
var sessionId = GetDebuggingSession();
257+
_encService.DiscardSolutionUpdate(sessionId);
258+
}
259+
335260
public void UpdateBaselines(Solution solution, ImmutableArray<ProjectId> projectIds)
336261
{
337262
var sessionId = GetDebuggingSession();

src/Features/Test/EditAndContinue/WatchHotReloadServiceTests.cs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
// See the LICENSE file in the project root for more information.
44

55
#if NET
6-
#nullable disable
76

87
using System;
98
using System.Collections.Immutable;
@@ -28,11 +27,15 @@ namespace Microsoft.CodeAnalysis.EditAndContinue.UnitTests;
2827
[UseExportProvider]
2928
public sealed class WatchHotReloadServiceTests : EditAndContinueWorkspaceTestBase
3029
{
31-
[Fact]
32-
public async Task Test()
30+
[Theory]
31+
[CombinatorialData]
32+
public async Task Test(bool requireCommit)
3333
{
3434
// See https://github.com/dotnet/sdk/blob/main/src/BuiltInTools/dotnet-watch/HotReload/CompilationHandler.cs#L125
3535

36+
// Note that xUnit does not run test case of a theory in parallel, so we can set global state here:
37+
WatchHotReloadService.RequireCommit = requireCommit;
38+
3639
var source1 = "class C { void M() { System.Console.WriteLine(1); } }";
3740
var source2 = "class C { void M() { System.Console.WriteLine(2); /*2*/} }";
3841
var source3 = "class C { void M() { System.Console.WriteLine(2); /*3*/} }";
@@ -69,7 +72,7 @@ public async Task Test()
6972
AssertEx.Equal(
7073
[
7174
"(A, MatchesBuildOutput)"
72-
], matchingDocuments.Select(e => (solution.GetDocument(e.id).Name, e.state)).OrderBy(e => e.Name).Select(e => e.ToString()));
75+
], matchingDocuments.Select(e => (solution.GetRequiredDocument(e.id).Name, e.state)).OrderBy(e => e.Name).Select(e => e.ToString()));
7376

7477
// Valid update:
7578
solution = solution.WithDocumentText(documentIdA, CreateText(source2));
@@ -79,6 +82,11 @@ public async Task Test()
7982
Assert.Equal(1, result.ProjectUpdates.Length);
8083
AssertEx.Equal([0x02000002], result.ProjectUpdates[0].UpdatedTypes);
8184

85+
if (requireCommit)
86+
{
87+
hotReload.CommitUpdate();
88+
}
89+
8290
// Insignificant change:
8391
solution = solution.WithDocumentText(documentIdA, CreateText(source3));
8492

@@ -113,6 +121,13 @@ public async Task Test()
113121
AssertEx.SetEqual(["P"], result.ProjectsToRestart.Select(p => solution.GetRequiredProject(p.Key).Name));
114122
AssertEx.SetEqual(["P"], result.ProjectsToRebuild.Select(p => solution.GetRequiredProject(p).Name));
115123

124+
if (requireCommit)
125+
{
126+
// Emulate the user making choice to not restart.
127+
// dotnet-watch then waits until Ctrl+R forces restart.
128+
hotReload.DiscardUpdate();
129+
}
130+
116131
// Syntax error:
117132
solution = solution.WithDocumentText(documentIdA, CreateText(source5));
118133

@@ -150,7 +165,7 @@ public async Task SourceGeneratorFailure()
150165
{
151166
generatorExecutionCount++;
152167

153-
var additionalText = context.AdditionalFiles.Single().GetText().ToString();
168+
var additionalText = context.AdditionalFiles.Single().GetText()!.ToString();
154169
if (additionalText.Contains("updated"))
155170
{
156171
throw new InvalidOperationException("Source generator failed");

0 commit comments

Comments
 (0)