Skip to content

Commit cd8d11c

Browse files
Merge pull request #187 from Project-Env/feature/186-use-embedded-cli-in-case-no-cli-is-available-on-the-path
Use embedded CLI in case it cannot be located on the PATH
2 parents 68c1cc4 + d547f82 commit cd8d11c

File tree

16 files changed

+109
-81
lines changed

16 files changed

+109
-81
lines changed

.github/workflows/build.yml

+5-3
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,13 @@ jobs:
3030
- uses: Project-Env/[email protected]
3131

3232
- run: |
33-
echo "ORG_GRADLE_PROJECT_githubUsername=${{ github.actor }}" >> $GITHUB_ENV
34-
echo "ORG_GRADLE_PROJECT_githubPassword=${{ secrets.GITHUB_TOKEN }}" >> $GITHUB_ENV
33+
echo "ORG_GRADLE_PROJECT_projectEnvCliUsername=${{ github.actor }}" >> $GITHUB_ENV
34+
echo "ORG_GRADLE_PROJECT_projectEnvCliPassword=${{ secrets.GITHUB_TOKEN }}" >> $GITHUB_ENV
35+
echo "ORG_GRADLE_PROJECT_projectEnvCommonsJavaUsername=${{ github.actor }}" >> $GITHUB_ENV
36+
echo "ORG_GRADLE_PROJECT_projectEnvCommonsJavaPassword=${{ secrets.GITHUB_TOKEN }}" >> $GITHUB_ENV
3537
3638
- name: Run Linters and Test
37-
run: gradle check
39+
run: gradle check koverXmlReport
3840

3941
- name: Verify Plugin Completeness
4042
run: gradle verifyPlugin

.github/workflows/release.yml

+4-2
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,10 @@ jobs:
2929
- uses: Project-Env/[email protected]
3030

3131
- run: |
32-
echo "ORG_GRADLE_PROJECT_githubUsername=${{ github.actor }}" >> $GITHUB_ENV
33-
echo "ORG_GRADLE_PROJECT_githubPassword=${{ secrets.GITHUB_TOKEN }}" >> $GITHUB_ENV
32+
echo "ORG_GRADLE_PROJECT_projectEnvCliUsername=${{ github.actor }}" >> $GITHUB_ENV
33+
echo "ORG_GRADLE_PROJECT_projectEnvCliPassword=${{ secrets.GITHUB_TOKEN }}" >> $GITHUB_ENV
34+
echo "ORG_GRADLE_PROJECT_projectEnvCommonsJavaUsername=${{ github.actor }}" >> $GITHUB_ENV
35+
echo "ORG_GRADLE_PROJECT_projectEnvCommonsJavaPassword=${{ secrets.GITHUB_TOKEN }}" >> $GITHUB_ENV
3436
3537
- name: Update Release
3638
id: release

build.gradle.kts

+13-20
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@ plugins {
77
// Java support
88
id("java")
99
// JaCoCo report support
10-
id("jacoco")
10+
id("org.jetbrains.kotlinx.kover") version "0.7.0-Alpha"
1111
// Kotlin support
12-
id("org.jetbrains.kotlin.jvm") version "1.8.10"
12+
id("org.jetbrains.kotlin.jvm") version "1.8.20"
1313
// gradle-intellij-plugin - read more: https://github.com/JetBrains/gradle-intellij-plugin
1414
id("org.jetbrains.intellij") version "1.13.3"
1515
// gradle-changelog-plugin - read more: https://github.com/JetBrains/gradle-changelog-plugin
1616
id("org.jetbrains.changelog") version "2.0.0"
1717
// ktlint linter - read more: https://github.com/JLLeitschuh/ktlint-gradle
18-
id("org.jlleitschuh.gradle.ktlint") version "11.0.0"
18+
id("org.jlleitschuh.gradle.ktlint") version "11.3.1"
1919
// Sonar support
2020
id("org.sonarqube") version "4.0.0.2929"
2121
}
@@ -28,15 +28,22 @@ repositories {
2828
mavenLocal()
2929
mavenCentral()
3030
maven {
31-
name = "github"
31+
name = "projectEnvCommonsJava"
3232
url = uri("https://maven.pkg.github.com/Project-Env/project-env-commons-java")
3333
credentials(PasswordCredentials::class)
3434
}
35+
maven {
36+
name = "projectEnvCli"
37+
url = uri("https://maven.pkg.github.com/Project-Env/project-env-cli")
38+
credentials(PasswordCredentials::class)
39+
}
3540
}
3641

3742
dependencies {
38-
val projectEnvCommonsVersion = "1.2.1"
43+
val projectEnvCliVersion = "3.15.0"
44+
implementation("io.projectenv.core:cli:$projectEnvCliVersion")
3945

46+
val projectEnvCommonsVersion = "1.2.1"
4047
implementation("io.projectenv.commons:process:$projectEnvCommonsVersion")
4148
implementation("io.projectenv.commons:gson:$projectEnvCommonsVersion")
4249
testImplementation("io.projectenv.commons:archive:$projectEnvCommonsVersion")
@@ -69,13 +76,10 @@ sonarqube {
6976
property("sonar.organization", "project-env")
7077
property("sonar.host.url", "https://sonarcloud.io")
7178
property("sonar.coverage.exclusions", "**/*Exception.kt")
79+
property("sonar.coverage.jacoco.xmlReportPaths", "build/reports/kover/report.xml")
7280
}
7381
}
7482

75-
jacoco {
76-
toolVersion = "0.8.8"
77-
}
78-
7983
tasks {
8084
properties("javaVersion").let {
8185
withType<JavaCompile> {
@@ -91,17 +95,6 @@ tasks {
9195
enabled = false
9296
}
9397

94-
jacocoTestReport {
95-
reports {
96-
xml.required.set(true)
97-
}
98-
dependsOn(test)
99-
}
100-
101-
test {
102-
finalizedBy(jacocoTestReport)
103-
}
104-
10598
patchPluginXml {
10699
version.set(properties("pluginVersion"))
107100
sinceBuild.set(properties("pluginSinceBuild"))

gradle.properties

+4-1
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,7 @@ javaVersion = 17
2828
# Opt-out flag for bundling Kotlin standard library.
2929
# See https://plugins.jetbrains.com/docs/intellij/kotlin.html#kotlin-standard-library for details.
3030
# suppress inspection "UnusedProperty"
31-
kotlin.stdlib.default.dependency = false
31+
kotlin.stdlib.default.dependency = false
32+
33+
34+
org.gradle.jvmargs=-Xmx1024m

project-env.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ tools_directory = ".tools"
22

33
[jdk]
44
distribution = "Temurin"
5-
distribution_version = "^17.0.5+8"
5+
distribution_version = "^17.0.6+10"
66

77
[gradle]
8-
version = "*7.6"
8+
version = "*8.0.2"

src/main/kotlin/io/projectenv/intellijplugin/listeners/GradleConfigurer.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class GradleConfigurer(val project: Project) : ProjectEnvToolsListener, GradleSe
3939
WriteAction.runAndWait<Throwable> {
4040
for (projectSettings in settings) {
4141
projectSettings.distributionType = DistributionType.LOCAL
42-
projectSettings.gradleHome = gradleInfo.toolBinariesRoot?.canonicalPath
42+
projectSettings.gradleHome = gradleInfo.toolBinariesRoot.get().canonicalPath
4343

4444
if (hasJdkInfo) {
4545
projectSettings.gradleJvm = ExternalSystemJdkUtil.USE_PROJECT_JDK

src/main/kotlin/io/projectenv/intellijplugin/listeners/JdkConfigurer.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class JdkConfigurer(val project: Project) : ProjectEnvToolsListener {
1414

1515
WriteAction.runAndWait<Throwable> {
1616
val jdkName = createJdkName()
17-
val newJdk = JavaSdk.getInstance().createJdk(jdkName, jdkInfo.toolBinariesRoot!!.canonicalPath, false)
17+
val newJdk = JavaSdk.getInstance().createJdk(jdkName, jdkInfo.toolBinariesRoot.get().canonicalPath, false)
1818

1919
val oldJdk = ProjectJdkTable.getInstance().findJdk(jdkName)
2020
if (oldJdk != null) {

src/main/kotlin/io/projectenv/intellijplugin/listeners/MavenConfigurer.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class MavenConfigurer(val project: Project) : ProjectEnvToolsListener {
1414

1515
WriteAction.runAndWait<Throwable> {
1616
val settings = MavenProjectsManager.getInstance(project)
17-
settings.generalSettings.mavenHome = mavenInfo.toolBinariesRoot!!.canonicalPath
17+
settings.generalSettings.mavenHome = mavenInfo.toolBinariesRoot.get().canonicalPath
1818

1919
val userSettingsFile = mavenInfo.unhandledProjectResources["userSettingsFile"]
2020
if (userSettingsFile != null) {

src/main/kotlin/io/projectenv/intellijplugin/listeners/NodeJsConfigurer.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class NodeJsConfigurer(val project: Project) : ProjectEnvToolsListener {
1313
val nodejsInfo = toolInfos.getToolInfo("nodejs") ?: return
1414

1515
WriteAction.runAndWait<Throwable> {
16-
val interpreter = NodeJsLocalInterpreter(nodejsInfo.primaryExecutable!!.canonicalPath)
16+
val interpreter = NodeJsLocalInterpreter(nodejsInfo.primaryExecutable.get().canonicalPath)
1717

1818
NodeJsLocalInterpreterManager.getInstance().interpreters.stream().filter { existingInterpreter ->
1919
interpreter.interpreterSystemDependentPath == existingInterpreter.interpreterSystemDependentPath

src/main/kotlin/io/projectenv/intellijplugin/listeners/ProjectEnvToolsRootExcluder.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ class ProjectEnvToolsRootExcluder(val project: Project) : ProjectEnvToolsListene
5050
}
5151

5252
val toolBinariesRootAsVirtualFile = VirtualFileManager.getInstance()
53-
.refreshAndFindFileByNioPath(info.toolBinariesRoot.toPath()) ?: continue
53+
.refreshAndFindFileByNioPath(info.toolBinariesRoot.get().toPath()) ?: continue
5454

5555
roots.add(toolBinariesRootAsVirtualFile)
5656
}

src/main/kotlin/io/projectenv/intellijplugin/services/impl/ProjectEnvServiceImpl.kt

+69-33
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,17 @@ import com.intellij.openapi.progress.ProgressManager
77
import com.intellij.openapi.progress.Task
88
import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator
99
import com.intellij.openapi.project.Project
10-
import io.projectenv.core.commons.process.ProcessEnvironmentHelper.getPathVariableName
10+
import io.projectenv.core.cli.ToolSupportHelper
11+
import io.projectenv.core.cli.configuration.ProjectEnvConfiguration
12+
import io.projectenv.core.cli.configuration.toml.TomlConfigurationFactory
13+
import io.projectenv.core.cli.index.DefaultToolsIndexManager
14+
import io.projectenv.core.cli.installer.DefaultLocalToolInstallationManager
1115
import io.projectenv.core.commons.process.ProcessHelper
1216
import io.projectenv.core.commons.process.ProcessResult
17+
import io.projectenv.core.toolsupport.spi.ImmutableToolSupportContext
18+
import io.projectenv.core.toolsupport.spi.ToolInfo
19+
import io.projectenv.core.toolsupport.spi.ToolSupport
20+
import io.projectenv.core.toolsupport.spi.ToolSupportContext
1321
import io.projectenv.intellijplugin.listeners.ProjectEnvTopics
1422
import io.projectenv.intellijplugin.notifications.ProjectEnvNotificationGroup
1523
import io.projectenv.intellijplugin.services.ProjectEnvCliResolverService
@@ -18,6 +26,7 @@ import io.projectenv.intellijplugin.services.ProjectEnvService
1826
import io.projectenv.intellijplugin.toolinfo.ToolInfoParser
1927
import io.projectenv.intellijplugin.toolinfo.ToolInfos
2028
import java.io.File
29+
import java.util.ServiceLoader
2130

2231
class ProjectEnvServiceImpl(val project: Project) : ProjectEnvService {
2332

@@ -26,29 +35,24 @@ class ProjectEnvServiceImpl(val project: Project) : ProjectEnvService {
2635
override fun refreshProjectEnv(sync: Boolean) {
2736
val configurationFile = project.service<ProjectEnvConfigFileResolverService>().resolveConfig() ?: return
2837

29-
val projectEnvCliExecutable = project.service<ProjectEnvCliResolverService>().resolveCli()
30-
if (projectEnvCliExecutable == null) {
31-
handleMissingCli()
32-
return
33-
}
34-
3538
runProcess("Installing Project-Env", sync) {
36-
val result = executeProjectEnvCli(projectEnvCliExecutable, configurationFile)
37-
if (isSuccessfulCliExecution(result)) {
38-
handleSuccessfulCliExecution(result)
39-
} else {
40-
handleCliExecutionFailure(result)
39+
try {
40+
val projectEnvCliExecutable = project.service<ProjectEnvCliResolverService>().resolveCli()
41+
42+
val toolInfos = if (projectEnvCliExecutable != null) {
43+
executeProjectEnvCliExecutable(projectEnvCliExecutable, configurationFile)
44+
} else {
45+
executeEmbeddedProjectEnvCli(configurationFile)
46+
}
47+
48+
project.messageBus.syncPublisher(ProjectEnvTopics.TOOLS_TOPIC).toolsUpdated(toolInfos)
49+
} catch (e: Exception) {
50+
ProjectEnvNotificationGroup.createNotification(e.message.orEmpty(), NotificationType.WARNING)
51+
.notify(project)
4152
}
4253
}
4354
}
4455

45-
private fun handleMissingCli() {
46-
ProjectEnvNotificationGroup.createNotification(
47-
"Could not resolve Project-Env CLI. Please make sure that the CLI is installed and on ${getPathVariableName()}.",
48-
NotificationType.WARNING
49-
).notify(project)
50-
}
51-
5256
private fun runProcess(title: String, sync: Boolean, runnable: Runnable) {
5357
if (sync) {
5458
ProgressManager.getInstance().runProcessWithProgressSynchronously(runnable, title, false, project)
@@ -64,7 +68,7 @@ class ProjectEnvServiceImpl(val project: Project) : ProjectEnvService {
6468
}
6569
}
6670

67-
private fun executeProjectEnvCli(projectEnvCliExecutable: File, configurationFile: File): ProcessResult {
71+
private fun executeProjectEnvCliExecutable(projectEnvCliExecutable: File, configurationFile: File): ToolInfos {
6872
val processBuilder = ProcessBuilder()
6973
.command(
7074
projectEnvCliExecutable.canonicalPath,
@@ -75,30 +79,62 @@ class ProjectEnvServiceImpl(val project: Project) : ProjectEnvService {
7579
)
7680
.directory(projectRoot)
7781

78-
return ProcessHelper.executeProcess(processBuilder, true, true)
82+
val result = ProcessHelper.executeProcess(processBuilder, true, true)
83+
if (isSuccessfulCliExecution(result)) {
84+
return ToolInfoParser.fromJson(result.stdOutput.get())
85+
} else {
86+
throw Exception("Failed to execute Project-Env CLI. See process output for more details:\n${result.errOutput.get()}")
87+
}
7988
}
8089

8190
private fun isSuccessfulCliExecution(result: ProcessResult): Boolean {
8291
return result.exitCode == 0
8392
}
8493

85-
private fun handleSuccessfulCliExecution(result: ProcessResult) {
86-
val toolDetails = parseRawToolDetails(result)
94+
private fun executeEmbeddedProjectEnvCli(configurationFile: File): ToolInfos {
95+
val configuration: ProjectEnvConfiguration = TomlConfigurationFactory.fromFile(configurationFile)
96+
val toolSupportContext = createToolSupportContext(configuration)
8797

88-
project.messageBus.syncPublisher(ProjectEnvTopics.TOOLS_TOPIC).toolsUpdated(toolDetails)
98+
val toolInstallationInfos = LinkedHashMap<String, List<ToolInfo>>()
99+
for (toolSupport in ServiceLoader.load(ToolSupport::class.java, ToolSupport::class.java.classLoader)) {
100+
val toolInfos: List<ToolInfo> = installOrUpdateTool(toolSupport, configuration, toolSupportContext)
101+
if (toolInfos.isNotEmpty()) {
102+
toolInstallationInfos[toolSupport.toolIdentifier] = toolInfos
103+
}
104+
}
105+
106+
return ToolInfos(toolInstallationInfos)
89107
}
90108

91-
private fun parseRawToolDetails(result: ProcessResult): ToolInfos {
92-
return ToolInfoParser.fromJson(result.stdOutput.get())
109+
private fun <T> installOrUpdateTool(
110+
toolSupport: ToolSupport<T>,
111+
configuration: ProjectEnvConfiguration,
112+
toolSupportContext: ToolSupportContext
113+
): List<ToolInfo> {
114+
val toolSupportConfigurationClass = ToolSupportHelper.getToolSupportConfigurationClass(toolSupport)
115+
val toolConfigurations =
116+
configuration.getToolConfigurations(toolSupport.toolIdentifier, toolSupportConfigurationClass)
117+
if (toolConfigurations.isEmpty()) {
118+
return emptyList()
119+
}
120+
121+
val toolInfos = ArrayList<ToolInfo>()
122+
for (toolConfiguration in toolConfigurations) {
123+
toolInfos.add(toolSupport.prepareTool(toolConfiguration, toolSupportContext))
124+
}
125+
return toolInfos
93126
}
94127

95-
private fun handleCliExecutionFailure(result: ProcessResult) {
96-
ProjectEnvNotificationGroup
97-
.createNotification(
98-
"Failed to execute Project-Env CLI. See process output for more details:\n${result.errOutput.get()}",
99-
NotificationType.WARNING
100-
)
101-
.notify(project)
128+
private fun createToolSupportContext(configuration: ProjectEnvConfiguration): ToolSupportContext {
129+
val toolsDirectory = File(projectRoot, configuration.toolsDirectory)
130+
val localToolInstallationManager = DefaultLocalToolInstallationManager(toolsDirectory)
131+
val toolsIndexManager = DefaultToolsIndexManager(toolsDirectory)
132+
133+
return ImmutableToolSupportContext.builder()
134+
.projectRoot(projectRoot)
135+
.localToolInstallationManager(localToolInstallationManager)
136+
.toolsIndexManager(toolsIndexManager)
137+
.build()
102138
}
103139

104140
override fun dispose() {

src/main/kotlin/io/projectenv/intellijplugin/toolinfo/ToolInfo.kt

-12
This file was deleted.

src/main/kotlin/io/projectenv/intellijplugin/toolinfo/ToolInfoParser.kt

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package io.projectenv.intellijplugin.toolinfo
22

33
import com.google.gson.reflect.TypeToken
44
import io.projectenv.commons.gson.GsonFactory
5+
import io.projectenv.core.toolsupport.spi.ToolInfo
56

67
object ToolInfoParser {
78
private val TOOL_INFOS_TYPE = object : TypeToken<Map<String, List<ToolInfo>>>() {}.type

src/main/kotlin/io/projectenv/intellijplugin/toolinfo/ToolInfos.kt

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.projectenv.intellijplugin.toolinfo
22

33
import io.projectenv.core.commons.process.ProcessEnvironmentHelper
4+
import io.projectenv.core.toolsupport.spi.ToolInfo
45
import java.io.File
56
import java.util.Collections
67

src/test/kotlin/io/projectenv/intellijplugin/listeners/ProjectEnvFilesListenerTest.kt

-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ class ProjectEnvFilesListenerTest : AbstractProjectEnvTest() {
1818
ProcessEnvironmentHelper.getPathVariableName(),
1919
ProcessEnvironmentHelper.createExtendedPathValue(pathElement)
2020
).execute {
21-
2221
copyResourceToProjectRootAndRefresh("project-env.toml")
2322
assertNotificationFired("Project-Env config file has been updated")
2423

src/test/kotlin/io/projectenv/intellijplugin/services/impl/ProjectEnvServiceImplTest.kt

+5-2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import java.io.File
2727
class ProjectEnvServiceImplTest : AbstractProjectEnvTest() {
2828

2929
@Test
30-
fun testRefreshFailsBecauseNoCliInstalled() {
30+
fun testRefreshUsesEmbeddedCli() {
3131
copyResourceToProjectRootAndRefresh("build.gradle")
3232
copyResourceToProjectRootAndRefresh("project-env.toml")
3333
clearFiredNotifications()
@@ -37,7 +37,10 @@ class ProjectEnvServiceImplTest : AbstractProjectEnvTest() {
3737
val service = project.service<ProjectEnvService>()
3838
service.refreshProjectEnv(true)
3939

40-
assertNotificationFired("Could not resolve Project-Env CLI", NotificationType.WARNING)
40+
assertMavenSettings()
41+
assertJdkSettings()
42+
assertNodeSettings()
43+
assertGradleSettings()
4144
}
4245

4346
@Test

0 commit comments

Comments
 (0)