[Scripting] Add authorization for Maven Resolver
This commit is contained in:
@@ -13,12 +13,12 @@ dependencies {
|
||||
compile("org.eclipse.aether:aether-util:1.1.0")
|
||||
compile("org.eclipse.aether:aether-connector-basic:1.1.0")
|
||||
compile("org.eclipse.aether:aether-transport-wagon:1.1.0")
|
||||
compile("org.eclipse.aether:aether-transport-http:1.1.0")
|
||||
compile("org.eclipse.aether:aether-transport-file:1.1.0")
|
||||
compile("org.apache.maven:maven-core:3.8.1")
|
||||
compile("org.apache.maven:maven-settings-builder:3.8.1")
|
||||
compile("org.apache.maven:maven-aether-provider:3.3.9")
|
||||
compile("org.apache.maven.wagon:wagon-provider-api:3.4.3")
|
||||
compile("org.apache.maven.wagon:wagon-http:3.4.3")
|
||||
testCompile(projectTests(":kotlin-scripting-dependencies"))
|
||||
testCompile(commonDep("junit"))
|
||||
testRuntimeOnly("org.slf4j:slf4j-nop:1.7.30")
|
||||
|
||||
+30
-19
@@ -17,13 +17,14 @@ import kotlin.script.experimental.api.SourceCode
|
||||
import kotlin.script.experimental.api.asSuccess
|
||||
import kotlin.script.experimental.dependencies.ExternalDependenciesResolver
|
||||
import kotlin.script.experimental.dependencies.RepositoryCoordinates
|
||||
import kotlin.script.experimental.dependencies.impl.makeResolveFailureResult
|
||||
import kotlin.script.experimental.dependencies.impl.toRepositoryUrlOrNull
|
||||
import kotlin.script.experimental.dependencies.impl.*
|
||||
import kotlin.script.experimental.dependencies.maven.impl.AetherResolveSession
|
||||
import kotlin.script.experimental.dependencies.maven.impl.mavenCentral
|
||||
import kotlin.script.experimental.dependencies.impl.dependencyScopes
|
||||
|
||||
|
||||
@Deprecated(
|
||||
"This class is not functional and left only for compatibility reasons. Use kotlin.script.experimental.dependencies.ExternalDependenciesResolver.Options for passing authorization options",
|
||||
replaceWith = ReplaceWith("RepositoryCoordinates(url)", "kotlin.script.experimental.dependencies.RepositoryCoordinates")
|
||||
)
|
||||
class MavenRepositoryCoordinates(
|
||||
url: String,
|
||||
val username: String?,
|
||||
@@ -89,21 +90,31 @@ class MavenDependenciesResolver : ExternalDependenciesResolver {
|
||||
val url = repositoryCoordinates.toRepositoryUrlOrNull()
|
||||
?: return false.asSuccess()
|
||||
val repoId = repositoryCoordinates.string.replace(FORBIDDEN_CHARS, "_")
|
||||
val repo = RemoteRepository.Builder(repoId, "default", url.toString())
|
||||
if (repositoryCoordinates is MavenRepositoryCoordinates) {
|
||||
val username = repositoryCoordinates.username?.let(::tryResolveEnvironmentVariable)
|
||||
val password = repositoryCoordinates.password?.let(::tryResolveEnvironmentVariable)
|
||||
if (username != null) {
|
||||
val auth = AuthenticationBuilder().apply {
|
||||
addUsername(username)
|
||||
if (password != null) {
|
||||
addPassword(password)
|
||||
}
|
||||
}
|
||||
repo.setAuthentication(auth.build())
|
||||
}
|
||||
}
|
||||
repos.add(repo.build())
|
||||
val repo = RemoteRepository.Builder(repoId, "default", url.toString()).apply {
|
||||
/**
|
||||
* Here we set all the authentication information we have, unconditionally.
|
||||
* Actual information that will be used (as well as lower-level checks,
|
||||
* such as nullability or emptiness) is determined by implementation.
|
||||
*
|
||||
* @see org.eclipse.aether.transport.wagon.WagonTransporter.getProxy
|
||||
* @see org.apache.maven.wagon.shared.http.AbstractHttpClientWagon.openConnectionInternal
|
||||
*/
|
||||
setAuthentication(
|
||||
AuthenticationBuilder().apply {
|
||||
val mavenRepo = repositoryCoordinates as? MavenRepositoryCoordinates
|
||||
val username = options.username ?: mavenRepo?.username
|
||||
val password = options.password ?: mavenRepo?.password
|
||||
addUsername(username?.let(::tryResolveEnvironmentVariable))
|
||||
addPassword(password?.let(::tryResolveEnvironmentVariable))
|
||||
addPrivateKey(
|
||||
options.privateKeyFile?.let(::tryResolveEnvironmentVariable),
|
||||
options.privateKeyPassphrase?.let(::tryResolveEnvironmentVariable)
|
||||
)
|
||||
}.build()
|
||||
)
|
||||
}.build()
|
||||
|
||||
repos.add(repo)
|
||||
return true.asSuccess()
|
||||
}
|
||||
|
||||
|
||||
+19
-3
@@ -11,6 +11,7 @@ import org.apache.maven.settings.Settings
|
||||
import org.apache.maven.settings.SettingsUtils
|
||||
import org.apache.maven.settings.TrackableBase
|
||||
import org.apache.maven.settings.building.*
|
||||
import org.codehaus.plexus.DefaultPlexusContainer
|
||||
import org.eclipse.aether.RepositorySystem
|
||||
import org.eclipse.aether.RepositorySystemSession
|
||||
import org.eclipse.aether.artifact.Artifact
|
||||
@@ -19,6 +20,8 @@ import org.eclipse.aether.collection.CollectRequest
|
||||
import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory
|
||||
import org.eclipse.aether.graph.Dependency
|
||||
import org.eclipse.aether.graph.DependencyFilter
|
||||
import org.eclipse.aether.internal.transport.wagon.PlexusWagonConfigurator
|
||||
import org.eclipse.aether.internal.transport.wagon.PlexusWagonProvider
|
||||
import org.eclipse.aether.repository.LocalRepository
|
||||
import org.eclipse.aether.repository.Proxy
|
||||
import org.eclipse.aether.repository.RemoteRepository
|
||||
@@ -29,7 +32,9 @@ import org.eclipse.aether.resolution.DependencyResult
|
||||
import org.eclipse.aether.spi.connector.RepositoryConnectorFactory
|
||||
import org.eclipse.aether.spi.connector.transport.TransporterFactory
|
||||
import org.eclipse.aether.transport.file.FileTransporterFactory
|
||||
import org.eclipse.aether.transport.http.HttpTransporterFactory
|
||||
import org.eclipse.aether.transport.wagon.WagonConfigurator
|
||||
import org.eclipse.aether.transport.wagon.WagonProvider
|
||||
import org.eclipse.aether.transport.wagon.WagonTransporterFactory
|
||||
import org.eclipse.aether.util.filter.DependencyFilterUtils
|
||||
import org.eclipse.aether.util.repository.AuthenticationBuilder
|
||||
import org.eclipse.aether.util.repository.DefaultMirrorSelector
|
||||
@@ -48,7 +53,7 @@ class AetherResolveSession(
|
||||
val remotes by lazy {
|
||||
val proxySelector = settings.getActiveProxy()?.let { proxy ->
|
||||
val selector = DefaultProxySelector()
|
||||
val auth = with (AuthenticationBuilder()) {
|
||||
val auth = with(AuthenticationBuilder()) {
|
||||
addUsername(proxy.username)
|
||||
addPassword(proxy.password)
|
||||
build()
|
||||
@@ -95,8 +100,19 @@ class AetherResolveSession(
|
||||
)
|
||||
locator.addService(
|
||||
TransporterFactory::class.java,
|
||||
HttpTransporterFactory::class.java
|
||||
WagonTransporterFactory::class.java
|
||||
)
|
||||
|
||||
val container = DefaultPlexusContainer()
|
||||
locator.setServices(
|
||||
WagonProvider::class.java,
|
||||
PlexusWagonProvider(container)
|
||||
)
|
||||
locator.setServices(
|
||||
WagonConfigurator::class.java,
|
||||
PlexusWagonConfigurator(container)
|
||||
)
|
||||
|
||||
locator.getService(RepositorySystem::class.java)
|
||||
}
|
||||
|
||||
|
||||
+24
-5
@@ -22,7 +22,7 @@ import kotlin.script.experimental.dependencies.impl.set
|
||||
@ExperimentalContracts
|
||||
class MavenResolverTest : ResolversTestBase() {
|
||||
|
||||
fun resolveAndCheck(
|
||||
private fun resolveAndCheck(
|
||||
coordinates: String,
|
||||
options: ExternalDependenciesResolver.Options = ExternalDependenciesResolver.Options.Empty,
|
||||
checkBody: (Iterable<File>) -> Boolean = { true }
|
||||
@@ -39,13 +39,18 @@ class MavenResolverTest : ResolversTestBase() {
|
||||
files.forEach { it.delete() }
|
||||
}
|
||||
|
||||
private fun buildOptions(vararg options: Pair<DependenciesResolverOptionsName, String>): ExternalDependenciesResolver.Options {
|
||||
return makeExternalDependenciesResolverOptions(mutableMapOf<String, String>().apply {
|
||||
for (option in options) this[option.first] = option.second
|
||||
})
|
||||
}
|
||||
|
||||
fun testResolveSimple() {
|
||||
resolveAndCheck("org.jetbrains.kotlin:kotlin-annotations-jvm:1.3.50") { files ->
|
||||
files.any { it.name.startsWith("kotlin-annotations-jvm") }
|
||||
}
|
||||
}
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
fun testResolveWithRuntime() {
|
||||
val compileOnly = "compile"
|
||||
val compileRuntime = "compile,runtime"
|
||||
@@ -54,9 +59,7 @@ class MavenResolverTest : ResolversTestBase() {
|
||||
listOf(compileOnly, compileRuntime).forEach { scopes ->
|
||||
resolveAndCheck(
|
||||
"org.uberfire:uberfire-io:7.39.0.Final",
|
||||
makeExternalDependenciesResolverOptions(buildMap {
|
||||
this[DependenciesResolverOptionsName.SCOPE] = scopes
|
||||
})
|
||||
buildOptions(DependenciesResolverOptionsName.SCOPE to scopes)
|
||||
) { files ->
|
||||
resolvedFilesCount[scopes] = files.count()
|
||||
files.any { it.name.startsWith("uberfire-commons") }
|
||||
@@ -81,6 +84,22 @@ class MavenResolverTest : ResolversTestBase() {
|
||||
}
|
||||
}
|
||||
|
||||
// Ignored - tests with custom repos often break the CI due to the caching issues
|
||||
// TODO: find a way to enable it back
|
||||
@Ignore
|
||||
fun ignore_testAuth() {
|
||||
val resolver = MavenDependenciesResolver()
|
||||
val options = buildOptions(
|
||||
DependenciesResolverOptionsName.USERNAME to "<FirstName.LastName>",
|
||||
DependenciesResolverOptionsName.PASSWORD to "<Space token>",
|
||||
)
|
||||
resolver.addRepository("https://packages.jetbrains.team/maven/p/crl/maven/", options)
|
||||
val files = runBlocking {
|
||||
resolver.resolve("com.jetbrains:space-sdk:1.0-dev")
|
||||
}.valueOrThrow()
|
||||
assertTrue(files.any { it.name.startsWith("space-sdk") })
|
||||
}
|
||||
|
||||
// Ignored - tests with custom repos often break the CI due to the caching issues
|
||||
// TODO: find a way to enable it back
|
||||
@Ignore
|
||||
|
||||
+29
-1
@@ -23,7 +23,11 @@ operator fun MutableMap<String, String>.set(key: DependenciesResolverOptionsName
|
||||
*/
|
||||
enum class DependenciesResolverOptionsName(optionName: String? = null) {
|
||||
TRANSITIVE,
|
||||
SCOPE;
|
||||
SCOPE,
|
||||
USERNAME,
|
||||
PASSWORD,
|
||||
KEY_FILE,
|
||||
KEY_PASSPHRASE;
|
||||
|
||||
val key = optionName ?: name.lowercase()
|
||||
}
|
||||
@@ -33,3 +37,27 @@ val ExternalDependenciesResolver.Options.transitive
|
||||
|
||||
val ExternalDependenciesResolver.Options.dependencyScopes
|
||||
get() = value(DependenciesResolverOptionsName.SCOPE)?.split(",")
|
||||
|
||||
/**
|
||||
* Username to access repository (should be passed with [password])
|
||||
*/
|
||||
val ExternalDependenciesResolver.Options.username
|
||||
get() = value(DependenciesResolverOptionsName.USERNAME)
|
||||
|
||||
/**
|
||||
* Password to access repository (should be passed with [username])
|
||||
*/
|
||||
val ExternalDependenciesResolver.Options.password
|
||||
get() = value(DependenciesResolverOptionsName.PASSWORD)
|
||||
|
||||
/**
|
||||
* Absolute path to the private key file to access repository
|
||||
*/
|
||||
val ExternalDependenciesResolver.Options.privateKeyFile
|
||||
get() = value(DependenciesResolverOptionsName.KEY_FILE)
|
||||
|
||||
/**
|
||||
* Passphrase to access file passed in [privateKeyFile]
|
||||
*/
|
||||
val ExternalDependenciesResolver.Options.privateKeyPassphrase
|
||||
get() = value(DependenciesResolverOptionsName.KEY_PASSPHRASE)
|
||||
|
||||
Reference in New Issue
Block a user