feat(plugins): Gate v2 framework compatibility
MODIFY
gate-plugins-test/src/main/kotlin/com/netflix/spinnaker/gate/plugins/GateApiExtension.kt
gate-plugins-test/src/main/kotlin/com/netflix/spinnaker/gate/plugins/GateApiExtension.kt
@@ -20,6 +20,7 @@ import com.netflix.spinnaker.gate.api.extension.ApiExtension
import com.netflix.spinnaker.gate.api.extension.HttpRequest
import com.netflix.spinnaker.gate.api.extension.HttpResponse
import com.netflix.spinnaker.kork.plugins.api.ExtensionConfiguration
+import com.netflix.spinnaker.kork.plugins.api.PluginConfiguration
import com.netflix.spinnaker.kork.plugins.api.PluginSdks
import javax.annotation.Nonnull
import org.pf4j.Extension
@@ -65,7 +66,7 @@ class GateApiExtension(
}
}
-@ExtensionConfiguration("api-extension")
+@PluginConfiguration("api-extension")
class ApiExtensionConfigProperties {
var id: String = "test"
}

MODIFY
gate-plugins-test/src/test/resources/gate-plugins-test.yml
gate-plugins-test/src/test/resources/gate-plugins-test.yml
@@ -33,6 +33,8 @@ slack:
spinnaker:
extensibility:
+ framework:
+ version: v2
plugins-root-path: build/plugins
plugins:
com.netflix.gate.enabled.plugin:

MODIFY
gate-proxy/src/main/kotlin/com/netflix/spinnaker/gate/controllers/ApiExtensionController.kt
gate-proxy/src/main/kotlin/com/netflix/spinnaker/gate/controllers/ApiExtensionController.kt
@@ -23,9 +23,7 @@ import com.netflix.spinnaker.kork.exceptions.SpinnakerException
import com.netflix.spinnaker.kork.exceptions.SystemException
import com.netflix.spinnaker.kork.web.exceptions.NotFoundException
import com.squareup.okhttp.internal.http.HttpMethod
-import java.io.IOException
-import java.util.stream.Collectors
-import javax.servlet.http.HttpServletRequest
+import org.springframework.beans.factory.ObjectProvider
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
@@ -34,6 +32,9 @@ import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController
+import java.io.IOException
+import java.util.stream.Collectors
+import javax.servlet.http.HttpServletRequest
/**
* A top-level [RestController] that exposes all api extensions under a common
@@ -42,10 +43,10 @@ import org.springframework.web.bind.annotation.RestController
@Alpha
@RestController
@RequestMapping("/extensions")
-class ApiExtensionController @Autowired constructor(private val apiExtensions: List<ApiExtension>) {
+class ApiExtensionController @Autowired constructor(private val apiExtensionsProvider: ObjectProvider<List<ApiExtension>>) {
init {
- val duplicateApiExtensionIds = apiExtensions
+ val duplicateApiExtensionIds = apiExtensionsProvider.getIfAvailable { ArrayList() }
.groupBy { it.id().toLowerCase() }
.filter { it.value.size > 1 }
.map { it.value }
@@ -82,7 +83,7 @@ class ApiExtensionController @Autowired constructor(private val apiExtensions: L
}
}
- val apiExtension = apiExtensions.stream()
+ val apiExtension = apiExtensionsProvider.getIfAvailable { ArrayList() }.stream()
.filter { e: ApiExtension -> e.id().equals(extension, ignoreCase = true) && e.handles(httpRequest) }
.findFirst()

MODIFY
gate-proxy/src/test/kotlin/com/netflix/spinnaker/gate/controllers/ApiExtensionControllerTest.kt
gate-proxy/src/test/kotlin/com/netflix/spinnaker/gate/controllers/ApiExtensionControllerTest.kt
@@ -24,6 +24,7 @@ import com.netflix.spinnaker.kork.web.exceptions.NotFoundException
import dev.minutest.junit.JUnit5Minutests
import dev.minutest.rootContext
import io.mockk.mockk
+import org.springframework.beans.factory.ObjectProvider
import strikt.api.expectThat
import strikt.api.expectThrows
import strikt.assertions.isEqualTo
@@ -36,13 +37,13 @@ class ApiExtensionControllerTest : JUnit5Minutests {
context("basic validation") {
test("raises SystemException when duplicate api extension identifiers are detected") {
expectThrows<SystemException> {
- ApiExtensionController(listOf(firstApiExtension, firstApiExtension))
+ ApiExtensionController(ApiExtensionsProvider(listOf(firstApiExtension, firstApiExtension)))
}
}
test("raises SystemException when duplicate api extension identifiers are detected") {
- ApiExtensionController(listOf(firstApiExtension))
- ApiExtensionController(listOf(firstApiExtension, secondApiExtension))
+ ApiExtensionController(ApiExtensionsProvider(listOf(firstApiExtension)))
+ ApiExtensionController(ApiExtensionsProvider(listOf(firstApiExtension, secondApiExtension)))
}
}
@@ -74,7 +75,7 @@ class ApiExtensionControllerTest : JUnit5Minutests {
private inner class Fixture {
val firstApiExtension = SimpleApiExtension("1")
val secondApiExtension = SimpleApiExtension("2")
- val subject = ApiExtensionController(listOf(firstApiExtension, secondApiExtension))
+ val subject = ApiExtensionController(ApiExtensionsProvider(listOf(firstApiExtension, secondApiExtension)))
}
class SimpleApiExtension(private val id: String) : ApiExtension {
@@ -90,4 +91,13 @@ class ApiExtensionControllerTest : JUnit5Minutests {
return HttpResponse.of(200, emptyMap(), "This is a result from ${id()}")
}
}
+
+ private inner class ApiExtensionsProvider(
+ private val apiExtensions: List<ApiExtension>
+ ) : ObjectProvider<List<ApiExtension>> {
+ override fun getIfUnique(): List<ApiExtension>? = apiExtensions
+ override fun getObject(vararg args: Any?): List<ApiExtension> = apiExtensions
+ override fun getObject(): List<ApiExtension> = apiExtensions
+ override fun getIfAvailable(): List<ApiExtension>? = apiExtensions
+ }
}

MODIFY
gate-web/gate-web.gradle
gate-web/gate-web.gradle
@@ -92,7 +92,8 @@ test {
String implementationVersion = getAttributes()["Implementation-Version"]
if (implementationVersion == null
|| implementationVersion.isEmpty()
- || implementationVersion == "undefined") {
+ || implementationVersion == "undefined"
+ || implementationVersion.endsWith("SNAPSHOT")) {
attributes(
'Implementation-Version': '1.0.0'
)

feat(plugins): Gate v2 framework compatibility (#1322)