diff --git a/RELEASES.md b/RELEASES.md index 0a73ccc7103b..6361eb17be6a 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -24,6 +24,10 @@ - Added support for evaluating one-shot expressions on the result values of arbitrary expressions ([#1749](https://github.com/enso-org/enso/pull/1749)). This is very useful for enabling more advanced introspection in the IDE. +- Added the `workspace/projectInfo` endpoint to the language server + ([#1759](https://github.com/enso-org/enso/pull/1759)). This allows the IDE to + get information about the running project in contexts where the project + manager isn't available or works differently. ## Libraries diff --git a/build.sbt b/build.sbt index 841ccbf8d127..a60ec536d2c9 100644 --- a/build.sbt +++ b/build.sbt @@ -915,13 +915,15 @@ lazy val `language-server` = (project in file("engine/language-server")) new TestFramework("org.scalameter.ScalaMeterFramework") ) ) - .dependsOn(`polyglot-api`) - .dependsOn(`json-rpc-server`) .dependsOn(`json-rpc-server-test` % Test) - .dependsOn(`text-buffer`) + .dependsOn(`json-rpc-server`) + .dependsOn(`logging-service`) + .dependsOn(`polyglot-api`) .dependsOn(`searcher`) + .dependsOn(`text-buffer`) + .dependsOn(`version-output`) + .dependsOn(pkg) .dependsOn(testkit % Test) - .dependsOn(`logging-service`) lazy val ast = (project in file("lib/scala/ast")) .settings( diff --git a/docs/language-server/protocol-language-server.md b/docs/language-server/protocol-language-server.md index b275f63ec888..10de96d3e8e9 100644 --- a/docs/language-server/protocol-language-server.md +++ b/docs/language-server/protocol-language-server.md @@ -98,6 +98,7 @@ transport formats, please look [here](./protocol-architecture). - [`text/applyEdit`](#textapplyedit) - [`text/didChange`](#textdidchange) - [Workspace Operations](#workspace-operations) + - [`workspace/projectInfo`](#workspaceprojectinfo) - [`workspace/undo`](#workspaceundo) - [`workspace/redo`](#workspaceredo) - [Monitoring](#monitoring) @@ -154,6 +155,7 @@ transport formats, please look [here](./protocol-architecture). - [`NotFile`](#notfile) - [`CannotOverwrite`](#cannotoverwrite) - [`ReadOutOfBounds`](#readoutofbounds) + - [`CannotDecode`](#cannotdecode) - [`StackItemNotFoundError`](#stackitemnotfounderror) - [`ContextNotFoundError`](#contextnotfounderror) - [`EmptyStackError`](#emptystackerror) @@ -2336,6 +2338,44 @@ null; The language server also has a set of operations useful for managing the client workspace. +### `workspace/projectInfo` + +This request allows the IDE to request information about the currently open +project in situations where it does not have a project manager to connect to. + +- **Type:** Request +- **Direction:** Client -> Server +- **Connection:** Protocol +- **Visibility:** Public + +#### Parameters + +```typescript +{ +} +``` + +#### Result + +```typescript +{ + // The name of the project. + projectName: String; + + // The engine version on which the project is running. + engineVersion: String; + + // The version of graal on which the project is running. + graalVersion: String; +} +``` + +#### Errors + +- [`CannotDecode`](#cannotdecode) if the project configuration cannot be + decoded. +- [`FileNotFound`](#filenotfound) if the project configuration cannot be found. + ### `workspace/undo` This request is sent from the client to the server to request that an operation @@ -3930,6 +3970,17 @@ Signals that the requested file read was out of bounds for the file's size. } ``` +### `CannotDecode` + +Signals that the project configuration cannot be decoded. + +```typescript +"error" : { + "code" : 1010 + "message" : "Cannot decode the project configuration" +} +``` + ```idl namespace org.enso.languageserver.protocol.binary; diff --git a/docs/language-server/protocol-project-manager.md b/docs/language-server/protocol-project-manager.md index 5e6bb3a3489b..93147071dc90 100644 --- a/docs/language-server/protocol-project-manager.md +++ b/docs/language-server/protocol-project-manager.md @@ -35,7 +35,7 @@ transport formats, please look [here](./protocol-architecture.md). - [`task/started`](#taskstarted) - [`task/progress-update`](#taskprogress-update) - [`task/finished`](#taskfinished) -- [Components Management](#components-management) +- [Runtime Version Management](#runtime-version-management) - [`engine/list-installed`](#enginelist-installed) - [`engine/list-available`](#enginelist-available) - [`engine/install`](#engineinstall) @@ -47,7 +47,7 @@ transport formats, please look [here](./protocol-architecture.md). - [Logging Service](#logging-service) - [`logging-service/get-endpoint`](#logging-serviceget-endpoint) - [Language Server Management](#language-server-management) -- [Errors](#errors-15) +- [Errors](#errors) - [`MissingComponentError`](#missingcomponenterror) - [`BrokenComponentError`](#brokencomponenterror) - [`ProjectManagerUpgradeRequired`](#projectmanagerupgraderequired) @@ -177,7 +177,7 @@ the action. #### Parameters ```typescript -interface ProjectOpenRequest { +{ projectId: UUID; /** @@ -192,7 +192,7 @@ interface ProjectOpenRequest { #### Result ```typescript -interface ProjectOpenResult { +{ /** * The version of the started language server represented by a semver version * string. @@ -208,6 +208,9 @@ interface ProjectOpenResult { * The endpoint used for binary protocol. */ languageServerBinaryAddress: IPWithSocket; + + // The name of the project as it is opened. + projectName: String; } ``` diff --git a/engine/language-server/src/main/scala/org/enso/languageserver/boot/MainModule.scala b/engine/language-server/src/main/scala/org/enso/languageserver/boot/MainModule.scala index 817b533a83fa..6a42c8a4ba91 100644 --- a/engine/language-server/src/main/scala/org/enso/languageserver/boot/MainModule.scala +++ b/engine/language-server/src/main/scala/org/enso/languageserver/boot/MainModule.scala @@ -247,7 +247,8 @@ class MainModule(serverConfig: LanguageServerConfig, logLevel: LogLevel) { stdOutController, stdErrController, stdInController, - runtimeConnector + runtimeConnector, + languageServerConfig ) log.trace( "Created JSON connection controller factory [{}].", diff --git a/engine/language-server/src/main/scala/org/enso/languageserver/data/Config.scala b/engine/language-server/src/main/scala/org/enso/languageserver/data/Config.scala index 6fbd80a85689..8ee6494c9415 100644 --- a/engine/language-server/src/main/scala/org/enso/languageserver/data/Config.scala +++ b/engine/language-server/src/main/scala/org/enso/languageserver/data/Config.scala @@ -173,3 +173,6 @@ case class Config( }.headOption } +object Config { + def ensoPackageConfigName: String = "package.yaml" +} diff --git a/engine/language-server/src/main/scala/org/enso/languageserver/filemanager/FileManagerApi.scala b/engine/language-server/src/main/scala/org/enso/languageserver/filemanager/FileManagerApi.scala index daa93a7be308..43d2f14dffe4 100644 --- a/engine/language-server/src/main/scala/org/enso/languageserver/filemanager/FileManagerApi.scala +++ b/engine/language-server/src/main/scala/org/enso/languageserver/filemanager/FileManagerApi.scala @@ -163,4 +163,7 @@ object FileManagerApi { case object NotDirectoryError extends Error(1006, "Path is not a directory") + case object CannotDecodeError + extends Error(1010, "Cannot decode the project configuration") + } diff --git a/engine/language-server/src/main/scala/org/enso/languageserver/protocol/json/JsonConnectionController.scala b/engine/language-server/src/main/scala/org/enso/languageserver/protocol/json/JsonConnectionController.scala index d32931ef0d71..50d10203deb6 100644 --- a/engine/language-server/src/main/scala/org/enso/languageserver/protocol/json/JsonConnectionController.scala +++ b/engine/language-server/src/main/scala/org/enso/languageserver/protocol/json/JsonConnectionController.scala @@ -1,7 +1,5 @@ package org.enso.languageserver.protocol.json -import java.util.UUID - import akka.actor.{Actor, ActorLogging, ActorRef, Props, Stash, Status} import akka.pattern.pipe import akka.util.Timeout @@ -14,6 +12,7 @@ import org.enso.languageserver.capability.CapabilityApi.{ ReleaseCapability } import org.enso.languageserver.capability.CapabilityProtocol +import org.enso.languageserver.data.Config import org.enso.languageserver.event.{ JsonSessionInitialized, JsonSessionTerminated @@ -41,6 +40,7 @@ import org.enso.languageserver.requesthandler.visualisation.{ ExecuteExpressionHandler, ModifyVisualisationHandler } +import org.enso.languageserver.requesthandler.workspace.ProjectInfoHandler import org.enso.languageserver.runtime.ContextRegistryProtocol import org.enso.languageserver.runtime.ExecutionApi._ import org.enso.languageserver.runtime.VisualisationApi.{ @@ -61,7 +61,9 @@ import org.enso.languageserver.session.SessionApi.{ import org.enso.languageserver.text.TextApi._ import org.enso.languageserver.text.TextProtocol import org.enso.languageserver.util.UnhandledLogging +import org.enso.languageserver.workspace.WorkspaceApi.ProjectInfo +import java.util.UUID import scala.concurrent.duration._ /** An actor handling communications between a single client and the language @@ -88,6 +90,7 @@ class JsonConnectionController( val stdErrController: ActorRef, val stdInController: ActorRef, val runtimeConnector: ActorRef, + val languageServerConfig: Config, requestTimeout: FiniteDuration = 10.seconds ) extends Actor with Stash @@ -280,7 +283,7 @@ class JsonConnectionController( private def createRequestHandlers( rpcSession: JsonSession - ): Map[Method, Props] = + ): Map[Method, Props] = { Map( Ping -> PingHandler.props( List( @@ -351,8 +354,10 @@ class JsonConnectionController( .props(stdErrController, rpcSession.clientId), RedirectStandardError -> RedirectStdErrHandler .props(stdErrController, rpcSession.clientId), - FeedStandardInput -> FeedStandardInputHandler.props(stdInController) + FeedStandardInput -> FeedStandardInputHandler.props(stdInController), + ProjectInfo -> ProjectInfoHandler.props(languageServerConfig) ) + } } @@ -382,6 +387,7 @@ object JsonConnectionController { stdErrController: ActorRef, stdInController: ActorRef, runtimeConnector: ActorRef, + languageServerConfig: Config, requestTimeout: FiniteDuration = 10.seconds ): Props = Props( @@ -397,6 +403,7 @@ object JsonConnectionController { stdErrController, stdInController, runtimeConnector, + languageServerConfig, requestTimeout ) ) diff --git a/engine/language-server/src/main/scala/org/enso/languageserver/protocol/json/JsonConnectionControllerFactory.scala b/engine/language-server/src/main/scala/org/enso/languageserver/protocol/json/JsonConnectionControllerFactory.scala index 6c459a753da4..38c88a9fe632 100644 --- a/engine/language-server/src/main/scala/org/enso/languageserver/protocol/json/JsonConnectionControllerFactory.scala +++ b/engine/language-server/src/main/scala/org/enso/languageserver/protocol/json/JsonConnectionControllerFactory.scala @@ -1,10 +1,11 @@ package org.enso.languageserver.protocol.json -import java.util.UUID - import akka.actor.{ActorRef, ActorSystem} import org.enso.jsonrpc.ClientControllerFactory import org.enso.languageserver.boot.resource.InitializationComponent +import org.enso.languageserver.data.Config + +import java.util.UUID /** Language server client controller factory. * @@ -23,7 +24,8 @@ class JsonConnectionControllerFactory( stdOutController: ActorRef, stdErrController: ActorRef, stdInController: ActorRef, - runtimeConnector: ActorRef + runtimeConnector: ActorRef, + config: Config )(implicit system: ActorSystem) extends ClientControllerFactory { @@ -45,7 +47,8 @@ class JsonConnectionControllerFactory( stdOutController, stdErrController, stdInController, - runtimeConnector + runtimeConnector, + config ) ) } diff --git a/engine/language-server/src/main/scala/org/enso/languageserver/protocol/json/JsonRpc.scala b/engine/language-server/src/main/scala/org/enso/languageserver/protocol/json/JsonRpc.scala index 52f3d87dd8ab..19754c108e7d 100644 --- a/engine/language-server/src/main/scala/org/enso/languageserver/protocol/json/JsonRpc.scala +++ b/engine/language-server/src/main/scala/org/enso/languageserver/protocol/json/JsonRpc.scala @@ -17,6 +17,7 @@ import org.enso.languageserver.search.SearchApi._ import org.enso.languageserver.runtime.VisualisationApi._ import org.enso.languageserver.session.SessionApi.InitProtocolConnection import org.enso.languageserver.text.TextApi._ +import org.enso.languageserver.workspace.WorkspaceApi.ProjectInfo object JsonRpc { @@ -62,6 +63,7 @@ object JsonRpc { .registerRequest(Completion) .registerRequest(Import) .registerRequest(RenameProject) + .registerRequest(ProjectInfo) .registerNotification(ForceReleaseCapability) .registerNotification(GrantCapability) .registerNotification(TextDidChange) @@ -74,5 +76,4 @@ object JsonRpc { .registerNotification(WaitingForStandardInput) .registerNotification(SuggestionsDatabaseUpdates) .registerNotification(VisualisationEvaluationFailed) - } diff --git a/engine/language-server/src/main/scala/org/enso/languageserver/requesthandler/workspace/ProjectInfoHandler.scala b/engine/language-server/src/main/scala/org/enso/languageserver/requesthandler/workspace/ProjectInfoHandler.scala new file mode 100644 index 000000000000..681f55af0267 --- /dev/null +++ b/engine/language-server/src/main/scala/org/enso/languageserver/requesthandler/workspace/ProjectInfoHandler.scala @@ -0,0 +1,70 @@ +package org.enso.languageserver.requesthandler.workspace + +import akka.actor.{Actor, ActorLogging, Props} +import buildinfo.Info +import org.enso.jsonrpc.{Request, ResponseError, ResponseResult} +import org.enso.languageserver.data.Config +import org.enso.languageserver.filemanager.FileManagerApi +import org.enso.languageserver.util.UnhandledLogging +import org.enso.languageserver.workspace.WorkspaceApi.ProjectInfo +import org.enso.logger.masking.MaskedPath +import org.enso.pkg.{Config => PkgConfig} + +import java.io.{File, FileInputStream} +import java.nio.charset.StandardCharsets + +/** A request handler for `workspace/openFile` commands. + */ +class ProjectInfoHandler(languageServerConfig: Config) + extends Actor + with ActorLogging + with UnhandledLogging { + + override def receive: Receive = { case Request(ProjectInfo, id, _) => + val projectRoot = languageServerConfig.directories.root.toPath.toFile + val configFile = new File(projectRoot, Config.ensoPackageConfigName) + + if (configFile.exists()) { + val projectConfig = PkgConfig.fromYaml( + new String( + new FileInputStream(configFile).readAllBytes(), + StandardCharsets.UTF_8 + ) + ) + if (projectConfig.isSuccess) { + val projectInfo = ProjectInfo.Result( + projectName = projectConfig.get.name, + engineVersion = Info.ensoVersion, + graalVersion = Info.graalVersion + ) + sender() ! ResponseResult( + ProjectInfo, + id, + projectInfo + ) + } else { + log.error( + "Could not decode the package configuration at [{}].", + MaskedPath(configFile.toPath) + ) + sender() ! ResponseError(Some(id), FileManagerApi.CannotDecodeError) + } + } else { + log.error( + "Could not find the package configuration in the project at [{}].", + MaskedPath(projectRoot.toPath) + ) + sender() ! ResponseError(Some(id), FileManagerApi.FileNotFoundError) + } + } +} +object ProjectInfoHandler { + + /** Creates a configuration object used to create a [[ProjectInfoHandler]]. + * + * @return a configuration object + */ + def props(languageServerConfig: Config): Props = Props( + new ProjectInfoHandler(languageServerConfig) + ) +} diff --git a/engine/language-server/src/main/scala/org/enso/languageserver/workspace/WorkspaceApi.scala b/engine/language-server/src/main/scala/org/enso/languageserver/workspace/WorkspaceApi.scala new file mode 100644 index 000000000000..8d2f4c6a5816 --- /dev/null +++ b/engine/language-server/src/main/scala/org/enso/languageserver/workspace/WorkspaceApi.scala @@ -0,0 +1,26 @@ +package org.enso.languageserver.workspace + +import org.enso.jsonrpc.{HasParams, HasResult, Method} + +/** The workspace management JSON RPC API provided by the language server. + * + * See [[https://github.com/enso-org/enso/blob/main/docs/language-server/README.md]] + * for message specifications. + */ +object WorkspaceApi { + + case object ProjectInfo extends Method("workspace/projectInfo") { + case class Params() + case class Result( + projectName: String, + engineVersion: String, + graalVersion: String + ) + implicit val hasParams = new HasParams[this.type] { + type Params = ProjectInfo.Params + } + implicit val hasResult = new HasResult[this.type] { + type Result = ProjectInfo.Result + } + } +} diff --git a/engine/language-server/src/test/resources/package.yaml b/engine/language-server/src/test/resources/package.yaml new file mode 100644 index 000000000000..2923e3659b2e --- /dev/null +++ b/engine/language-server/src/test/resources/package.yaml @@ -0,0 +1,6 @@ +license: APLv2 +name: Standard +enso-version: default +version: "0.1.0" +author: "Enso Team " +maintainer: "Enso Team " diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/BaseServerTest.scala b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/BaseServerTest.scala index 6b338f016191..72fb0a95595f 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/BaseServerTest.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/BaseServerTest.scala @@ -1,8 +1,5 @@ package org.enso.languageserver.websocket.json -import java.nio.file.Files -import java.util.UUID - import akka.testkit.TestProbe import io.circe.literal._ import org.apache.commons.io.FileUtils @@ -37,6 +34,8 @@ import org.enso.polyglot.runtime.Runtime.Api import org.enso.searcher.sql.{SqlDatabase, SqlSuggestionsRepo, SqlVersionsRepo} import org.enso.text.Sha3_224VersionCalculator +import java.nio.file.Files +import java.util.UUID import scala.concurrent.Await import scala.concurrent.duration._ @@ -186,7 +185,8 @@ class BaseServerTest extends JsonRpcServerTestKit { stdOutController, stdErrController, stdInController, - runtimeConnectorProbe.ref + runtimeConnectorProbe.ref, + config ) } diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/WorkspaceOperationsTest.scala b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/WorkspaceOperationsTest.scala new file mode 100644 index 000000000000..d7c7140bf60b --- /dev/null +++ b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/WorkspaceOperationsTest.scala @@ -0,0 +1,97 @@ +package org.enso.languageserver.websocket.json + +import buildinfo.Info +import io.circe.literal.JsonStringContext +import org.enso.languageserver.data.Config +import org.enso.testkit.FlakySpec + +import java.io.{File, FileOutputStream} + +class WorkspaceOperationsTest extends BaseServerTest with FlakySpec { + + "workspace/projectInfo" must { + val packageConfigName = Config.ensoPackageConfigName + val testYamlPath = new File(testContentRoot.toFile, packageConfigName) + + "return the project info" taggedAs Flaky in { + testYamlPath.delete() + val packageYamlContents = + getClass.getClassLoader.getResourceAsStream(packageConfigName) + val yamlOutStream = new FileOutputStream(testYamlPath) + yamlOutStream.write(packageYamlContents.readAllBytes()) + yamlOutStream.close() + + val client = getInitialisedWsClient() + + client.send(json""" + { "jsonrpc": "2.0", + "method": "workspace/projectInfo", + "id": 1, + "params": {} + } + """) + + client.expectJson(json""" + { "jsonrpc": "2.0", + "id": 1, + "result": { + "projectName" : "Standard", + "engineVersion" : ${Info.ensoVersion}, + "graalVersion" : ${Info.graalVersion} + } + } + """) + } + + "return an error when the project configuration cannot be decoded" in { + testYamlPath.delete() + val yamlOutStream = new FileOutputStream(testYamlPath) + yamlOutStream.write(0x00) + yamlOutStream.close() + + val client = getInitialisedWsClient() + + client.send(json""" + { "jsonrpc": "2.0", + "method": "workspace/projectInfo", + "id": 1, + "params": {} + } + """) + + client.expectJson(json""" + { "jsonrpc": "2.0", + "id": 1, + "error": { + "code": 1010, + "message": "Cannot decode the project configuration" + } + } + """) + } + + "return an error when the project configuration is not present" in { + testYamlPath.delete() + + val client = getInitialisedWsClient() + + client.send(json""" + { "jsonrpc": "2.0", + "method": "workspace/projectInfo", + "id": 1, + "params": {} + } + """) + + client.expectJson(json""" + { "jsonrpc": "2.0", + "id": 1, + "error": { + "code": 1003, + "message": "File not found" + } + } + """) + } + } +} diff --git a/lib/scala/project-manager/src/main/scala/org/enso/projectmanager/data/RunningLanguageServerInfo.scala b/lib/scala/project-manager/src/main/scala/org/enso/projectmanager/data/RunningLanguageServerInfo.scala index f1634a4f6894..7b6834aa60d7 100644 --- a/lib/scala/project-manager/src/main/scala/org/enso/projectmanager/data/RunningLanguageServerInfo.scala +++ b/lib/scala/project-manager/src/main/scala/org/enso/projectmanager/data/RunningLanguageServerInfo.scala @@ -6,8 +6,10 @@ import nl.gn0s1s.bump.SemVer * * @param engineVersion the version of the started language server * @param sockets the sockets listened by the language server + * @param projectName the name of the project */ case class RunningLanguageServerInfo( engineVersion: SemVer, - sockets: LanguageServerSockets + sockets: LanguageServerSockets, + projectName: String ) diff --git a/lib/scala/project-manager/src/main/scala/org/enso/projectmanager/protocol/ProjectManagementApi.scala b/lib/scala/project-manager/src/main/scala/org/enso/projectmanager/protocol/ProjectManagementApi.scala index a166d924d18f..1abb3a30727f 100644 --- a/lib/scala/project-manager/src/main/scala/org/enso/projectmanager/protocol/ProjectManagementApi.scala +++ b/lib/scala/project-manager/src/main/scala/org/enso/projectmanager/protocol/ProjectManagementApi.scala @@ -76,7 +76,8 @@ object ProjectManagementApi { case class Result( engineVersion: SemVer, languageServerJsonAddress: Socket, - languageServerBinaryAddress: Socket + languageServerBinaryAddress: Socket, + projectName: String ) implicit val hasParams = new HasParams[this.type] { diff --git a/lib/scala/project-manager/src/main/scala/org/enso/projectmanager/requesthandler/ProjectOpenHandler.scala b/lib/scala/project-manager/src/main/scala/org/enso/projectmanager/requesthandler/ProjectOpenHandler.scala index 18187fdd182d..0eae0be11e62 100644 --- a/lib/scala/project-manager/src/main/scala/org/enso/projectmanager/requesthandler/ProjectOpenHandler.scala +++ b/lib/scala/project-manager/src/main/scala/org/enso/projectmanager/requesthandler/ProjectOpenHandler.scala @@ -54,7 +54,8 @@ class ProjectOpenHandler[F[+_, +_]: Exec: CovariantFlatMap]( } yield ProjectOpen.Result( engineVersion = server.engineVersion, languageServerJsonAddress = server.sockets.jsonSocket, - languageServerBinaryAddress = server.sockets.binarySocket + languageServerBinaryAddress = server.sockets.binarySocket, + projectName = server.projectName ) } diff --git a/lib/scala/project-manager/src/main/scala/org/enso/projectmanager/service/ProjectService.scala b/lib/scala/project-manager/src/main/scala/org/enso/projectmanager/service/ProjectService.scala index dc2842b38a0d..ffd55b6cfc26 100644 --- a/lib/scala/project-manager/src/main/scala/org/enso/projectmanager/service/ProjectService.scala +++ b/lib/scala/project-manager/src/main/scala/org/enso/projectmanager/service/ProjectService.scala @@ -311,7 +311,7 @@ class ProjectService[ s"Language server boot failed. ${th.getMessage}" ) } - } yield RunningLanguageServerInfo(version, sockets) + } yield RunningLanguageServerInfo(version, sockets, project.name) /** @inheritdoc */ override def closeProject( diff --git a/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/ProjectManagementOps.scala b/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/ProjectManagementOps.scala index e5df9563a90a..60c261baba9f 100644 --- a/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/ProjectManagementOps.scala +++ b/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/ProjectManagementOps.scala @@ -1,7 +1,6 @@ package org.enso.projectmanager import java.util.UUID - import akka.testkit.TestDuration import io.circe.Json import io.circe.syntax._ @@ -10,6 +9,7 @@ import org.enso.pkg.SemVerJson._ import io.circe.parser.parse import nl.gn0s1s.bump.SemVer import org.enso.projectmanager.data.{MissingComponentAction, Socket} +import org.enso.projectmanager.protocol.ProjectManagementApi.ProjectOpen import scala.concurrent.duration._ @@ -70,6 +70,26 @@ trait ProjectManagementOps { this: BaseServerSpec => socket.fold(fail(s"Failed to decode json: $openReply", _), identity) } + def openProjectData(implicit client: WsTestClient): ProjectOpen.Result = { + val Right(openReply) = parse(client.expectMessage(20.seconds.dilated)) + val openResult = for { + result <- openReply.hcursor.downExpectedField("result") + engineVer <- result.downField("engineVersion").as[SemVer] + jsonAddr <- result.downExpectedField("languageServerJsonAddress") + jsonHost <- jsonAddr.downField("host").as[String] + jsonPort <- jsonAddr.downField("port").as[Int] + binAddr <- result.downExpectedField("languageServerBinaryAddress") + binHost <- binAddr.downField("host").as[String] + binPort <- binAddr.downField("port").as[Int] + name <- result.downField("projectName").as[String] + } yield { + val jsonSock = Socket(jsonHost, jsonPort) + val binSock = Socket(binHost, binPort) + ProjectOpen.Result(engineVer, jsonSock, binSock, name) + } + openResult.getOrElse(throw new Exception("Should have worked.")) + } + def closeProject( projectId: UUID )(implicit client: WsTestClient): Unit = { diff --git a/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/ProjectManagementApiSpec.scala b/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/ProjectManagementApiSpec.scala index 98a15e8f6014..43a78b611ef7 100644 --- a/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/ProjectManagementApiSpec.scala +++ b/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/ProjectManagementApiSpec.scala @@ -303,6 +303,26 @@ class ProjectManagementApiSpec "project/open" must { + "open a project" taggedAs Flaky in { + val projectName = "Test_Project" + implicit val client: WsTestClient = new WsTestClient(address) + val projectId = createProject(projectName) + client.send(json""" + { "jsonrpc": "2.0", + "method": "project/open", + "id": 0, + "params": { + "projectId": $projectId + } + } + """) + val result = openProjectData + result.projectName shouldEqual projectName + result.engineVersion shouldEqual SemVer("0.0.1").get + closeProject(projectId) + deleteProject(projectId) + } + "fail when project doesn't exist" in { val client = new WsTestClient(address) client.send(json""" diff --git a/tools/legal-review/engine/report-state b/tools/legal-review/engine/report-state index f01ec1bbf3ba..a9565ff44424 100644 --- a/tools/legal-review/engine/report-state +++ b/tools/legal-review/engine/report-state @@ -1,3 +1,3 @@ -F22125736BE5D0452B568F45CE4A76EBEF27F339469B9DD3F5476B43369DBEB3 +99F30FC4FA243330ADBC746BDB8F5B7CF2DD82FB7C4E023F1ED29B231395B46A DBB6898C0166DF679A4179FFFADD4CD98C48D42AF072CA168FED27B41E1C3E43 0