Skip to content
Draft
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
1 change: 1 addition & 0 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ pipeline {
branch 'master'
branch 'develop'
branch 'rc/*'
branch 'poc/*'
}
}
steps {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ trait ProjectConfigurationProvider {
def getMainFile(folder: String): Option[Future[String]]
def getProjectRoot(folder: String): Option[Future[String]] =
getMainFile(folder).map(_.map(m => m.substring(0, m.lastIndexOf(Fs.separatorChar))))

/**
* Iterates through the folder to extract each project inside.
* @param folder
* @return by default each root folder is the root of the project
*/
def getProjectsFromFolder(folder: String): Future[Seq[String]] = Future.successful(Seq(folder))
}

object IgnoreProjectConfigurationAdapter extends ProjectConfigurationProvider {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,14 @@ class WorkspaceManager protected (

override def initialize(workspaceFolders: List[WorkspaceFolder]): Future[Unit] = {
val newWorkspaces = extractCleanURIs(workspaceFolders)
workspaces
.initialize(newWorkspaces)
.map { _ => // Drop all old workspaces
dependencies.foreach(d => d.withUnitAccessor(this))
}
val newProjects = Future.sequence(newWorkspaces.map(projectConfigurationProvider.getProjectsFromFolder)).map(_.flatten)
newProjects.flatMap(projects =>
workspaces
.initialize(projects)
.map { _ => // Drop all old workspaces
dependencies.foreach(d => d.withUnitAccessor(this))
}
)
}

private def extractCleanURIs(workspaceFolders: List[WorkspaceFolder]) =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#%RAML 1.0
title: a
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#%RAML 1.0
title: b
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#%RAML 1.0
title: b
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#%RAML 1.0
title: c
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#%RAML 1.0
title: d
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#%RAML 1.0
title: a
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#%RAML 1.0
title: d
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#%RAML 1.0
title: a
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#%RAML 1.0
title: d

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package org.mulesoft.als.server.workspace.multiproject

import org.mulesoft.als.common.PlatformDirectoryResolver
import org.mulesoft.als.server.client.scala.LanguageServerBuilder
import org.mulesoft.als.server.modules.WorkspaceManagerFactoryBuilder
import org.mulesoft.als.server.protocol.LanguageServer
import org.mulesoft.als.server.protocol.configuration.AlsInitializeParams
import org.mulesoft.als.server.textsync.TextDocumentContainer
import org.mulesoft.als.server.{LanguageServerBaseTest, MockDiagnosticClientNotifier, MockFilesInClientNotifier}
import org.mulesoft.amfintegration.amfconfiguration.EditorConfiguration
import org.mulesoft.lsp.configuration.TraceKind
import org.scalatest.compatible.Assertion

import scala.concurrent.ExecutionContext

class MultiProjectConfigurationProviderTest extends LanguageServerBaseTest {

override implicit val executionContext: ExecutionContext = ExecutionContext.Implicits.global

override def rootPath: String = "workspace/multi-project"

def buildServer(alsClient: Option[MockFilesInClientNotifier] = None): LanguageServer = {
val container = TextDocumentContainer()
val editorConfiguration = EditorConfiguration()
val builder =
new WorkspaceManagerFactoryBuilder(
new MockDiagnosticClientNotifier,
editorConfiguration,
Option(TestMultiProjectConfigurationProvider(container, editorConfiguration, new PlatformDirectoryResolver(container.platform)))
)


val maybeInProjectManager = alsClient.map(builder.filesInProjectManager)
val factory = builder.buildWorkspaceManagerFactory()

val b = new LanguageServerBuilder(
factory.documentManager,
factory.workspaceManager,
factory.configurationManager,
factory.resolutionTaskManager
)
maybeInProjectManager.foreach(b.addInitializableModule)
b.build()
}

val defaultInitializationParams: AlsInitializeParams = AlsInitializeParams(None, Some(TraceKind.Off), rootPath = Some(filePath("")))

test("Configuration provider reads multiple projects in folder") {
val totalProjects = 4
val provider = TestMultiProjectConfigurationProvider(TextDocumentContainer(), EditorConfiguration(), new PlatformDirectoryResolver(platform))
for{
projectPaths <- provider.getProjectsFromFolder(filePath(""))
} yield {
(0 until totalProjects).map(1+).map(r => s"project$r").foreach(name => assert(projectPaths.map(_.split("/").last).contains(name)))
projectPaths.length shouldBe totalProjects
}
}

test("initialize correct projects for rootPath") {
withServer[Assertion](buildServer(), defaultInitializationParams) { server =>
server.workspaceFolders().length shouldBe 4
}
}

test("get correct main file for project") {
val notifier = new MockFilesInClientNotifier
withServer[Assertion](buildServer(Some(notifier)), defaultInitializationParams) { server =>
for {
_ <- setMainFile(server)(filePath("project1"), "api.raml")
filesInProject <- notifier.nextCall
} yield {
filesInProject.uris.size shouldBe 1
filesInProject.uris.head.endsWith("project1/api.raml") shouldBe true
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.mulesoft.als.server.workspace.multiproject

import org.mulesoft.als.common.DirectoryResolver
import org.mulesoft.als.server.modules.workspace.DefaultProjectConfigurationProvider
import org.mulesoft.als.server.textsync.TextDocumentContainer
import org.mulesoft.amfintegration.amfconfiguration.EditorConfiguration
import org.mulesoft.amfintegration.amfconfiguration.executioncontext.Implicits.global

import scala.concurrent.Future


case class TestMultiProjectConfigurationProvider(
container: TextDocumentContainer,
editorConfiguration: EditorConfiguration,
directoryResolver: DirectoryResolver
) extends DefaultProjectConfigurationProvider(container, editorConfiguration) {
private def isProject(folder: String): Boolean = folder.split("/").last.startsWith("project")

override def getProjectsFromFolder(folder: String): Future[Seq[String]] = {
if(isProject(folder)) Future.successful(Seq(folder))
else {
directoryResolver.isDirectory(folder).flatMap{
case true =>
directoryResolver.readDir(folder)
case false =>
Future.successful(Seq.empty)
}.flatMap(folders => Future.sequence(folders.map(trailSlash(folder).concat).map(getProjectsFromFolder)).map(_.flatten))
}
}
private def trailSlash(f: String): String =
if (f.endsWith("/")) f else s"$f/"
}
2 changes: 1 addition & 1 deletion dependencies.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version=7.1.0-SNAPSHOT
version=7.1.0-MULTI-PROJECT-SNAPSHOT
amf=5.7.0
amf.custom-validator.js=1.7.2
amf.custom-validator-scalajs=0.7.0
Expand Down