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
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,7 @@ package final class RunFeatureModel: ObservableObject {
package var configurationSaveError: String? { service.configurationSaveError }
package var projectToolchain: ProjectToolchainSelection { service.projectToolchain }
package var blockingToolchainDiagnostic: RunConfigurationDiagnostic? {
service.configurationDiagnostics.first {
$0.code == "missingToolchain" || $0.code == "toolchainVersionMismatch"
}
service.blockingToolchainDiagnostic(for: service.selectedConfiguration)
}
package var sourceSearchRoots: [URL] { service.sourceSearchRoots }

Expand Down
23 changes: 22 additions & 1 deletion macos/Sources/LitheExecutionModule/Services/RunService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,7 @@ package final class RunService: ObservableObject {
fail("Project run configuration is missing. Identify the project before running.")
return
}
if let diagnostic = configurationDiagnostics.first(where: { Self.isBlockingToolchainDiagnostic($0) }) {
if let diagnostic = blockingToolchainDiagnostic(for: configuration) {
fail(diagnostic.message)
return
}
Expand Down Expand Up @@ -636,6 +636,16 @@ package final class RunService: ObservableObject {
return descriptor.id != "java"
}

package func blockingToolchainDiagnostic(
for configuration: RunConfiguration?
) -> RunConfigurationDiagnostic? {
configurationDiagnostics.first { diagnostic in
Self.isBlockingToolchainDiagnostic(diagnostic)
&& (diagnostic.configurationID == nil
|| diagnostic.configurationID == configuration?.id)
}
}

private static func isBlockingToolchainDiagnostic(_ diagnostic: RunConfigurationDiagnostic) -> Bool {
diagnostic.code == "missingToolchain" || diagnostic.code == "toolchainVersionMismatch"
}
Expand Down Expand Up @@ -866,6 +876,17 @@ package final class RunService: ObservableObject {
guard configurationStatus == .ready,
let projectURL else { return }
moduleSessions.removeAll { $0.id == configuration.id }
if let diagnostic = blockingToolchainDiagnostic(for: configuration) {
moduleSessions.append(RunSession(
id: configuration.id,
configurationID: configuration.id,
title: configuration.name,
output: diagnostic.message + "\n",
isRunning: false,
exitCode: 1
))
return
}
if extensionRequiredLanguageIDs.contains(configuration.kind.providerID),
languageRunExtension(providerID: configuration.kind.providerID) == nil {
moduleSessions.append(RunSession(
Expand Down
69 changes: 66 additions & 3 deletions macos/Tests/LitheTests/RunConfigurationIntegrationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2674,6 +2674,64 @@ struct RunConfigurationIntegrationTests {
#expect(requests[1].environment?["JAVA_HOME"] == nil)
}

@Test
func scopedNodeDiagnosticBlocksOnlyTheFrontendService() async throws {
let backend = JavaRunConfiguration(
id: "module:backend",
name: "backend",
kind: .mavenModule,
execution: .service,
modulePath: "backend",
mainClass: nil
)
let frontend = RunConfiguration(
id: "npm.script:web/dev",
name: "dev",
kind: .process(provider: "npm.script"),
execution: .service,
modulePath: nil,
mainClass: nil
)
let backendPlan = SharedLaunchPlan(
executable: .toolchain("project-maven"),
arguments: ["spring-boot:run"],
workingDirectory: "."
)
let diagnostic = RunConfigurationDiagnostic(
configurationID: frontend.id,
code: "missingToolchain",
message: "No local node toolchain is selected"
)
let fixture = makeFixture(
status: .ready,
effective: [backend, frontend].map {
EffectiveRunConfiguration(configuration: $0, options: RunOptions())
},
plans: [backend.id: backendPlan],
diagnostics: [diagnostic]
)

await fixture.service.loadProject(
at: fixture.root,
files: [],
mavenProject: fixture.mavenProject
)
fixture.service.runAllServices()

#expect(fixture.operations.launchPlanIDs == [backend.id])
#expect(fixture.processFactory.processes.count == 1)
let backendSession = try #require(
fixture.service.moduleSessions.first(where: { $0.id == backend.id })
)
let frontendSession = try #require(
fixture.service.moduleSessions.first(where: { $0.id == frontend.id })
)
#expect(backendSession.isRunning)
#expect(!frontendSession.isRunning)
#expect(frontendSession.exitCode == 1)
#expect(frontendSession.output.contains("No local node toolchain"))
}

@Test
func serviceAddressUsesExplicitArgumentsAndEnvironmentPorts() async throws {
let argumentService = JavaRunConfiguration(
Expand Down Expand Up @@ -3789,6 +3847,7 @@ struct RunConfigurationIntegrationTests {
plans: [String: SharedLaunchPlan] = [:],
generationEntryCount: Int? = nil,
defaultConfigurationID: String? = nil,
diagnostics: [RunConfigurationDiagnostic] = [],
preferences: RunTestKeyValueStore = RunTestKeyValueStore()
) -> RunServiceFixture {
let root = URL(fileURLWithPath: "/tmp/lithe-run-service", isDirectory: true)
Expand All @@ -3797,7 +3856,8 @@ struct RunConfigurationIntegrationTests {
effective: effective,
plans: plans,
generationEntryCount: generationEntryCount,
defaultConfigurationID: defaultConfigurationID
defaultConfigurationID: defaultConfigurationID,
diagnostics: diagnostics
)
let process = RecordingStreamingProcess()
let processFactory = RecordingProcessFactory()
Expand Down Expand Up @@ -3942,6 +4002,7 @@ private final class RecordingRunConfigurationOperations: RunConfigurationOperati
let plans: [String: SharedLaunchPlan]
let generationEntryCount: Int?
let defaultConfigurationID: String?
let diagnostics: [RunConfigurationDiagnostic]
private(set) var resolveCalls = 0
private(set) var migrationCalls = 0
private(set) var launchPlanIDs: [String] = []
Expand All @@ -3959,13 +4020,15 @@ private final class RecordingRunConfigurationOperations: RunConfigurationOperati
effective: [EffectiveRunConfiguration],
plans: [String: SharedLaunchPlan],
generationEntryCount: Int? = nil,
defaultConfigurationID: String? = nil
defaultConfigurationID: String? = nil,
diagnostics: [RunConfigurationDiagnostic] = []
) {
self.status = status
self.effective = effective
self.plans = plans
self.generationEntryCount = generationEntryCount
self.defaultConfigurationID = defaultConfigurationID
self.diagnostics = diagnostics
}

func inspect(at projectURL: URL) -> ProjectRunConfigurationInspection {
Expand All @@ -3985,7 +4048,7 @@ private final class RecordingRunConfigurationOperations: RunConfigurationOperati
}
return RunConfigurationResolution(
configurations: effective,
diagnostics: [],
diagnostics: diagnostics,
defaultConfigurationID: defaultConfigurationID
)
}
Expand Down
Loading
Loading