Skip to content
This repository has been archived by the owner on Jan 11, 2022. It is now read-only.

Commit

Permalink
Provides custom plugin labels for all Skaffold deployments for serve…
Browse files Browse the repository at this point in the history
…r-side metrics. (#71)

* Provide custom plugin labels for all Skaffold deployments.
  • Loading branch information
ivanporty authored Nov 8, 2018
1 parent 1966779 commit d89bc93
Show file tree
Hide file tree
Showing 13 changed files with 267 additions and 2 deletions.
19 changes: 19 additions & 0 deletions core/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright 2018 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

dependencies {
testCompile(project(":common-test-lib"))
}
44 changes: 44 additions & 0 deletions core/src/main/kotlin/com/google/container/tools/core/PluginInfo.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright 2018 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.container.tools.core

import com.intellij.ide.plugins.IdeaPluginDescriptor
import com.intellij.ide.plugins.PluginManager
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.extensions.PluginId
import com.intellij.util.PlatformUtils

const val CONTAINER_TOOLS_PLUGIN_ID = "com.google.container.tools"
const val UNKNOWN_VERSION = "unknown"

/** Utilities to get common plugin information such as its version. */
class PluginInfo {
companion object {
val instance: PluginInfo
get() = ServiceManager.getService(PluginInfo::class.java)!!
}

/** Version of the plugin installed, or `N/A` if version cannot be determined. */
val pluginVersion: String by lazy {
val ideaPluginDescriptor: IdeaPluginDescriptor? =
PluginManager.getPlugin(PluginId.getId(CONTAINER_TOOLS_PLUGIN_ID))

ideaPluginDescriptor?.version ?: UNKNOWN_VERSION
}

val platformPrefix: String by lazy { PlatformUtils.getPlatformPrefix() }
}
22 changes: 22 additions & 0 deletions core/src/main/resources/META-INF/core.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<!--
~ Copyright 2018 Google Inc. All Rights Reserved.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->

<!-- Declares core/utility IDE extensions and components for Container Tools -->
<idea-plugin>
<extensions defaultExtensionNs="com.intellij">
<applicationService serviceImplementation="com.google.container.tools.core.PluginInfo"/>
</extensions>
</idea-plugin>
1 change: 1 addition & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
*/

include 'core'
include 'skaffold'
include 'skaffold-editing'
include 'common-test-lib'
1 change: 1 addition & 0 deletions skaffold/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@
*/

dependencies {
compile(project(":core"))
testCompile(project(":common-test-lib"))
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,13 @@ abstract class SkaffoldExecutorService {
add("--filename")
add(it)
}
settings.skaffoldLabels?.let {
it.labels
.forEach { label ->
add("--label")
add("${label.key}=${label.value}")
}
}
}

return SkaffoldProcess(
Expand Down Expand Up @@ -84,11 +91,13 @@ abstract class SkaffoldExecutorService {
* configuration file. If not provided, default `skaffold.yaml` used.
* @property workingDirectory Optional, working directory where Skaffold needs to be launched.
* This is usually set to project working directory.
* @property skaffoldLabels Kubernetes style labels to pass to Skaffold execution.
*/
data class SkaffoldExecutorSettings(
val executionMode: ExecutionMode,
val skaffoldConfigurationFilePath: String? = null,
var workingDirectory: File? = null
val workingDirectory: File? = null,
val skaffoldLabels: SkaffoldLabels? = null
) {

/** Execution mode for Skaffold, single run, continuous development, etc. */
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright 2018 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.container.tools.skaffold

import com.google.common.annotations.VisibleForTesting
import com.google.container.tools.core.PluginInfo
import com.intellij.openapi.application.ApplicationInfo

const val IDE_LABEL = "ide"
const val IDE_VERSION_LABEL = "ideVersion"
const val PLUGIN_VERSION_LABEL = "ijPluginVersion"

/**
* Maintains list of Kubernetes labels - string based key-value pairs used by Skaffold to apply
* to all deployments. [getDefaultLabels] function supplies default set of labels used for all
* deployments.
*/
class SkaffoldLabels {
companion object {
/**
* Default set of labels for all Skaffold-based deployments. Includes IDE type and
* version, plugin version.
*/
val defaultLabels: SkaffoldLabels by lazy {
populateDefaultLabels()
}

@VisibleForTesting
fun populateDefaultLabels(): SkaffoldLabels {
return SkaffoldLabels().apply {
this.labels[IDE_LABEL] = PluginInfo.instance.platformPrefix
this.labels[IDE_VERSION_LABEL] = ApplicationInfo.getInstance().getStrictVersion()
this.labels[PLUGIN_VERSION_LABEL] = PluginInfo.instance.pluginVersion
}
}
}

val labels: MutableMap<String, String> = mutableMapOf()
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package com.google.container.tools.skaffold.run

import com.google.container.tools.skaffold.SkaffoldExecutorService
import com.google.container.tools.skaffold.SkaffoldExecutorSettings
import com.google.container.tools.skaffold.SkaffoldLabels
import com.google.container.tools.skaffold.message
import com.intellij.execution.ExecutionException
import com.intellij.execution.configurations.CommandLineState
Expand Down Expand Up @@ -69,7 +70,8 @@ class SkaffoldCommandLineState(
SkaffoldExecutorSettings(
executionMode,
skaffoldConfigurationFilePath,
workingDirectory = File(environment.project.basePath)
workingDirectory = File(environment.project.basePath),
skaffoldLabels = SkaffoldLabels.defaultLabels
)
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,58 @@ class DefaultSkaffoldExecutorServiceTest {

verify { defaultSkaffoldExecutorService.createProcess(File("/tmp"), any()) }
}

@Test
fun `empty skaffold label list does not generate label flags`() {
val skaffoldLabels = SkaffoldLabels()

val result = defaultSkaffoldExecutorService.executeSkaffold(
SkaffoldExecutorSettings(
SkaffoldExecutorSettings.ExecutionMode.DEV,
skaffoldConfigurationFilePath = "test.yaml",
skaffoldLabels = skaffoldLabels
)
)

assertThat(result.commandLine).isEqualTo("skaffold dev --filename test.yaml")
}

@Test
fun `single skaffold label list generates correct label flag`() {
val skaffoldLabels = SkaffoldLabels()
skaffoldLabels.labels["ide"] = "testIde"

val result = defaultSkaffoldExecutorService.executeSkaffold(
SkaffoldExecutorSettings(
SkaffoldExecutorSettings.ExecutionMode.DEV,
skaffoldConfigurationFilePath = "test.yaml",
skaffoldLabels = skaffoldLabels
)
)

assertThat(result.commandLine).isEqualTo(
"skaffold dev --filename test.yaml --label ide=testIde"
)
}

@Test
fun `multiple skaffold label list generates correct label flag set`() {
val skaffoldLabels = SkaffoldLabels()
skaffoldLabels.labels["ide"] = "testIde"
skaffoldLabels.labels["name"] = "unitTest"
skaffoldLabels.labels["version"] = "1"

val result = defaultSkaffoldExecutorService.executeSkaffold(
SkaffoldExecutorSettings(
SkaffoldExecutorSettings.ExecutionMode.DEV,
skaffoldConfigurationFilePath = "test.yaml",
skaffoldLabels = skaffoldLabels
)
)

assertThat(result.commandLine).isEqualTo(
"skaffold dev --filename test.yaml " +
"--label ide=testIde --label name=unitTest --label version=1"
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright 2018 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.container.tools.skaffold

import com.google.common.truth.Truth.assertThat
import com.google.container.tools.core.PluginInfo
import com.google.container.tools.test.ContainerToolsRule
import com.google.container.tools.test.TestService
import com.intellij.openapi.application.ApplicationInfo
import io.mockk.every
import io.mockk.impl.annotations.MockK
import org.junit.Rule
import org.junit.Test

/** Unit tests for [SkaffoldLabels] class. */
class SkaffoldLabelsTest {
@get:Rule
val containerToolsRule = ContainerToolsRule(this)

@MockK
@TestService
private lateinit var mockApplicationInfo: ApplicationInfo
@MockK
@TestService
private lateinit var mockPluginInfo: PluginInfo

@Test
fun `valid default skaffold labels are constructed from IDE and plugin information`() {
// mock all sources of information that should be used for default labels
every { mockApplicationInfo.strictVersion } answers { "999.9" }
every { mockPluginInfo.platformPrefix } answers { "TestIde" }
every { mockPluginInfo.pluginVersion } answers { "0.1" }

val defaultLabels: SkaffoldLabels = SkaffoldLabels.populateDefaultLabels()

assertThat(defaultLabels.labels["ide"]).isEqualTo("TestIde")
assertThat(defaultLabels.labels["ideVersion"]).isEqualTo("999.9")
assertThat(defaultLabels.labels["ijPluginVersion"]).isEqualTo("0.1")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package com.google.container.tools.skaffold.run

import com.google.common.truth.Truth.assertThat
import com.google.container.tools.core.PluginInfo
import com.google.container.tools.skaffold.SkaffoldExecutorService
import com.google.container.tools.skaffold.SkaffoldExecutorSettings
import com.google.container.tools.skaffold.SkaffoldProcess
Expand Down Expand Up @@ -56,6 +57,9 @@ class SkaffoldCommandLineStateTest {
@MockK
@TestService
private lateinit var mockSkaffoldExecutorService: SkaffoldExecutorService
@MockK
@TestService
private lateinit var mockPluginInfoService: PluginInfo

private val skaffoldSettingsCapturingSlot: CapturingSlot<SkaffoldExecutorSettings> = slot()

Expand Down
1 change: 1 addition & 0 deletions skaffold/src/test/resources/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@
<id>com.google.container.tools</id>
<name>Google Container Tools</name>

<xi:include href="/META-INF/core.xml" xpointer="xpointer(/idea-plugin/*)"/>
<xi:include href="/META-INF/skaffold.xml" xpointer="xpointer(/idea-plugin/*)"/>
</idea-plugin>
1 change: 1 addition & 0 deletions src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

<depends>com.intellij.modules.lang</depends>

<xi:include href="/META-INF/core.xml" xpointer="xpointer(/idea-plugin/*)"/>
<xi:include href="/META-INF/skaffold.xml" xpointer="xpointer(/idea-plugin/*)"/>
<xi:include href="/META-INF/skaffold-editing.xml" xpointer="xpointer(/idea-plugin/*)"/>

Expand Down

0 comments on commit d89bc93

Please sign in to comment.