Skip to content

Commit dbc2e7b

Browse files
oheger-boschsschuberth
authored andcommittedFeb 25, 2025
refactor(Maven): Move extension functions to a separate file
This makes the functions easier to find, and it also breaks a cyclic dependency between `MavenSupport` and `LocalProjectWorkspaceReader`. Signed-off-by: Oliver Heger <oliver.heger@bosch.io>
1 parent 7655ba1 commit dbc2e7b

File tree

4 files changed

+244
-190
lines changed

4 files changed

+244
-190
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
* Copyright (C) 2017 The ORT Project Authors (see <https://github.com/oss-review-toolkit/ort/blob/main/NOTICE>)
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* SPDX-License-Identifier: Apache-2.0
17+
* License-Filename: LICENSE
18+
*/
19+
20+
package org.ossreviewtoolkit.plugins.packagemanagers.maven.utils
21+
22+
import org.apache.maven.artifact.repository.Authentication
23+
import org.apache.maven.bridge.MavenRepositorySystem
24+
import org.apache.maven.repository.Proxy
25+
26+
import org.eclipse.aether.RepositorySystemSession
27+
import org.eclipse.aether.artifact.Artifact
28+
import org.eclipse.aether.repository.AuthenticationContext
29+
import org.eclipse.aether.repository.RemoteRepository
30+
31+
fun Artifact.identifier() = "$groupId:$artifactId:$version"
32+
33+
/**
34+
* Convert this [RemoteRepository] to a repository in the format used by the Maven Repository System.
35+
* Make sure that all relevant properties are set, especially the proxy and authentication.
36+
*/
37+
internal fun RemoteRepository.toArtifactRepository(
38+
repositorySystemSession: RepositorySystemSession,
39+
repositorySystem: MavenRepositorySystem,
40+
id: String
41+
) = repositorySystem.createRepository(url, id, true, null, true, null, null).apply {
42+
this@toArtifactRepository.proxy?.also { repoProxy ->
43+
proxy = Proxy().apply {
44+
host = repoProxy.host
45+
port = repoProxy.port
46+
protocol = repoProxy.type
47+
toMavenAuthentication(
48+
AuthenticationContext.forProxy(
49+
repositorySystemSession,
50+
this@toArtifactRepository
51+
)
52+
)?.also { authentication ->
53+
userName = authentication.username
54+
password = authentication.password
55+
}
56+
}
57+
}
58+
59+
this@toArtifactRepository.authentication?.also {
60+
authentication = toMavenAuthentication(
61+
AuthenticationContext.forRepository(
62+
repositorySystemSession,
63+
this@toArtifactRepository
64+
)
65+
)
66+
}
67+
}
68+
69+
/**
70+
* Return authentication information for an artifact repository based on the given [authContext]. The
71+
* libraries involved use different approaches to model authentication.
72+
*/
73+
private fun toMavenAuthentication(authContext: AuthenticationContext?): Authentication? =
74+
authContext?.let {
75+
Authentication(
76+
it[AuthenticationContext.USERNAME],
77+
it[AuthenticationContext.PASSWORD]
78+
).apply {
79+
passphrase = it[AuthenticationContext.PRIVATE_KEY_PASSPHRASE]
80+
privateKey = it[AuthenticationContext.PRIVATE_KEY_PATH]
81+
}
82+
}

‎plugins/package-managers/maven/src/main/kotlin/utils/MavenSupport.kt

-56
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import java.net.URI
2626
import kotlin.time.Duration.Companion.hours
2727

2828
import org.apache.logging.log4j.kotlin.logger
29-
import org.apache.maven.artifact.repository.Authentication
3029
import org.apache.maven.artifact.repository.LegacyLocalRepositoryManager
3130
import org.apache.maven.bridge.MavenRepositorySystem
3231
import org.apache.maven.execution.DefaultMavenExecutionRequest
@@ -43,7 +42,6 @@ import org.apache.maven.project.ProjectBuildingException
4342
import org.apache.maven.project.ProjectBuildingRequest
4443
import org.apache.maven.project.ProjectBuildingResult
4544
import org.apache.maven.properties.internal.EnvironmentUtils
46-
import org.apache.maven.repository.Proxy
4745
import org.apache.maven.session.scope.internal.SessionScope
4846

4947
import org.codehaus.plexus.DefaultContainerConfiguration
@@ -60,7 +58,6 @@ import org.eclipse.aether.artifact.Artifact
6058
import org.eclipse.aether.artifact.DefaultArtifact
6159
import org.eclipse.aether.impl.RemoteRepositoryManager
6260
import org.eclipse.aether.impl.RepositoryConnectorProvider
63-
import org.eclipse.aether.repository.AuthenticationContext
6461
import org.eclipse.aether.repository.RemoteRepository
6562
import org.eclipse.aether.repository.WorkspaceReader
6663
import org.eclipse.aether.resolution.ArtifactDescriptorRequest
@@ -93,8 +90,6 @@ import org.ossreviewtoolkit.utils.ort.okHttpClient
9390
import org.ossreviewtoolkit.utils.ort.ortDataDirectory
9491
import org.ossreviewtoolkit.utils.ort.showStackTrace
9592

96-
fun Artifact.identifier() = "$groupId:$artifactId:$version"
97-
9893
/**
9994
* Return the path to this file or a corresponding message if the file is unknown.
10095
*/
@@ -644,57 +639,6 @@ internal fun isTychoProject(file: File): Boolean {
644639
} == true
645640
}
646641

647-
/**
648-
* Convert this [RemoteRepository] to a repository in the format used by the Maven Repository System.
649-
* Make sure that all relevant properties are set, especially the proxy and authentication.
650-
*/
651-
internal fun RemoteRepository.toArtifactRepository(
652-
repositorySystemSession: RepositorySystemSession,
653-
repositorySystem: MavenRepositorySystem,
654-
id: String
655-
) = repositorySystem.createRepository(url, id, true, null, true, null, null).apply {
656-
this@toArtifactRepository.proxy?.also { repoProxy ->
657-
proxy = Proxy().apply {
658-
host = repoProxy.host
659-
port = repoProxy.port
660-
protocol = repoProxy.type
661-
toMavenAuthentication(
662-
AuthenticationContext.forProxy(
663-
repositorySystemSession,
664-
this@toArtifactRepository
665-
)
666-
)?.also { authentication ->
667-
userName = authentication.username
668-
password = authentication.password
669-
}
670-
}
671-
}
672-
673-
this@toArtifactRepository.authentication?.also {
674-
authentication = toMavenAuthentication(
675-
AuthenticationContext.forRepository(
676-
repositorySystemSession,
677-
this@toArtifactRepository
678-
)
679-
)
680-
}
681-
}
682-
683-
/**
684-
* Return authentication information for an artifact repository based on the given [authContext]. The
685-
* libraries involved use different approaches to model authentication.
686-
*/
687-
private fun toMavenAuthentication(authContext: AuthenticationContext?): Authentication? =
688-
authContext?.let {
689-
Authentication(
690-
it[AuthenticationContext.USERNAME],
691-
it[AuthenticationContext.PASSWORD]
692-
).apply {
693-
passphrase = it[AuthenticationContext.PRIVATE_KEY_PASSPHRASE]
694-
privateKey = it[AuthenticationContext.PRIVATE_KEY_PATH]
695-
}
696-
}
697-
698642
/**
699643
* Return true if an artifact that has not been requested from Maven Central is also available on Maven Central
700644
* but with a different hash, otherwise return false.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
/*
2+
* Copyright (C) 2025 The ORT Project Authors (see <https://github.com/oss-review-toolkit/ort/blob/main/NOTICE>)
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* SPDX-License-Identifier: Apache-2.0
17+
* License-Filename: LICENSE
18+
*/
19+
20+
@file:Suppress("DEPRECATION") // Required for the deprecated ArtifactRepository interface.
21+
22+
package org.ossreviewtoolkit.plugins.packagemanagers.maven.utils
23+
24+
import io.kotest.core.spec.style.WordSpec
25+
import io.kotest.matchers.shouldBe
26+
27+
import io.mockk.every
28+
import io.mockk.just
29+
import io.mockk.mockk
30+
import io.mockk.runs
31+
import io.mockk.slot
32+
import io.mockk.verify
33+
34+
import org.apache.maven.artifact.repository.Authentication
35+
import org.apache.maven.bridge.MavenRepositorySystem
36+
import org.apache.maven.repository.Proxy as MavenProxy
37+
38+
import org.eclipse.aether.RepositorySystemSession
39+
import org.eclipse.aether.repository.Proxy
40+
import org.eclipse.aether.repository.RemoteRepository
41+
import org.eclipse.aether.util.repository.AuthenticationBuilder
42+
43+
class ExtensionsTest : WordSpec({
44+
"toArtifactRepository()" should {
45+
"create a plain artifact repository from a remote repository" {
46+
val repositoryId = "aTestRepository"
47+
val repository = RemoteRepository.Builder("ignoredId", null, REPOSITORY_URL).build()
48+
49+
val session = mockk<RepositorySystemSession>()
50+
val artifactRepository = mockk<org.apache.maven.artifact.repository.ArtifactRepository>()
51+
val repositorySystem = mockk<MavenRepositorySystem> {
52+
every {
53+
createRepository(REPOSITORY_URL, repositoryId, true, null, true, null, null)
54+
} returns artifactRepository
55+
}
56+
57+
repository.toArtifactRepository(session, repositorySystem, repositoryId) shouldBe artifactRepository
58+
}
59+
60+
"create an artifact repository with a configured proxy" {
61+
val repository = RemoteRepository.Builder("someId", "someType", REPOSITORY_URL)
62+
.setProxy(Proxy("http", "proxy.example.com", 8080))
63+
.build()
64+
65+
val session = mockk<RepositorySystemSession>()
66+
val artifactRepository = mockk<org.apache.maven.artifact.repository.ArtifactRepository> {
67+
every { proxy = any() } just runs
68+
}
69+
70+
val repositorySystem = mockk<MavenRepositorySystem> {
71+
every {
72+
createRepository(any(), any(), true, null, true, null, null)
73+
} returns artifactRepository
74+
}
75+
76+
repository.toArtifactRepository(session, repositorySystem, "id") shouldBe artifactRepository
77+
78+
val slotProxy = slot<MavenProxy>()
79+
verify {
80+
artifactRepository.proxy = capture(slotProxy)
81+
}
82+
83+
with(slotProxy.captured) {
84+
host shouldBe "proxy.example.com"
85+
port shouldBe 8080
86+
protocol shouldBe "http"
87+
}
88+
}
89+
90+
"create an artifact repository with authentication" {
91+
val repository = RemoteRepository.Builder("someId", "someType", REPOSITORY_URL)
92+
.setAuthentication(
93+
AuthenticationBuilder()
94+
.addUsername("scott")
95+
.addPassword("tiger".toCharArray())
96+
.addPrivateKey("privateKeyPath", "passphrase")
97+
.build()
98+
).build()
99+
100+
val session = mockk<RepositorySystemSession>()
101+
val artifactRepository = mockk<org.apache.maven.artifact.repository.ArtifactRepository> {
102+
every { authentication = any() } just runs
103+
}
104+
105+
val repositorySystem = mockk<MavenRepositorySystem> {
106+
every {
107+
createRepository(any(), any(), true, null, true, null, null)
108+
} returns artifactRepository
109+
}
110+
111+
repository.toArtifactRepository(session, repositorySystem, "id") shouldBe artifactRepository
112+
113+
val slotAuth = slot<Authentication>()
114+
verify {
115+
artifactRepository.authentication = capture(slotAuth)
116+
}
117+
118+
with(slotAuth.captured) {
119+
username shouldBe "scott"
120+
password shouldBe "tiger"
121+
privateKey shouldBe "privateKeyPath"
122+
passphrase shouldBe "passphrase"
123+
}
124+
}
125+
126+
"create an artifact repository with a configured proxy that requires authentication" {
127+
val proxyAuth = AuthenticationBuilder()
128+
.addUsername("proxyUser")
129+
.addPassword("proxyPassword".toCharArray())
130+
.build()
131+
val repository = RemoteRepository.Builder("someId", "someType", REPOSITORY_URL)
132+
.setProxy(Proxy("http", "proxy.example.com", 8080, proxyAuth))
133+
.build()
134+
135+
val session = mockk<RepositorySystemSession>()
136+
val artifactRepository = mockk<org.apache.maven.artifact.repository.ArtifactRepository> {
137+
every { proxy = any() } just runs
138+
}
139+
140+
val repositorySystem = mockk<MavenRepositorySystem> {
141+
every {
142+
createRepository(any(), any(), true, null, true, null, null)
143+
} returns artifactRepository
144+
}
145+
146+
repository.toArtifactRepository(session, repositorySystem, "id") shouldBe artifactRepository
147+
148+
val slotProxy = slot<MavenProxy>()
149+
verify {
150+
artifactRepository.proxy = capture(slotProxy)
151+
}
152+
153+
with(slotProxy.captured) {
154+
userName shouldBe "proxyUser"
155+
password shouldBe "proxyPassword"
156+
}
157+
}
158+
}
159+
})
160+
161+
/** A test repository URL. */
162+
private const val REPOSITORY_URL = "https://example.com/repo"

‎plugins/package-managers/maven/src/test/kotlin/utils/MavenSupportTest.kt

-134
Original file line numberDiff line numberDiff line change
@@ -23,143 +23,9 @@ import io.kotest.core.spec.style.WordSpec
2323
import io.kotest.engine.spec.tempdir
2424
import io.kotest.matchers.shouldBe
2525

26-
import io.mockk.every
27-
import io.mockk.just
28-
import io.mockk.mockk
29-
import io.mockk.runs
30-
import io.mockk.slot
31-
import io.mockk.verify
32-
33-
import org.apache.maven.artifact.repository.Authentication
34-
import org.apache.maven.bridge.MavenRepositorySystem
35-
import org.apache.maven.repository.Proxy as MavenProxy
36-
37-
import org.eclipse.aether.RepositorySystemSession
38-
import org.eclipse.aether.repository.Proxy
39-
import org.eclipse.aether.repository.RemoteRepository
40-
import org.eclipse.aether.util.repository.AuthenticationBuilder
41-
4226
import org.ossreviewtoolkit.plugins.packagemanagers.maven.addTychoExtension
4327

4428
class MavenSupportTest : WordSpec({
45-
@Suppress("DEPRECATION") // For deprecated ArtifactRepository interface.
46-
"toArtifactRepository()" should {
47-
"create a plain artifact repository from a remote repository" {
48-
val repositoryId = "aTestRepository"
49-
val repositoryUrl = "https://example.com/repo"
50-
val repository = RemoteRepository.Builder("ignoredId", null, repositoryUrl).build()
51-
52-
val session = mockk<RepositorySystemSession>()
53-
val artifactRepository = mockk<org.apache.maven.artifact.repository.ArtifactRepository>()
54-
val repositorySystem = mockk<MavenRepositorySystem> {
55-
every {
56-
createRepository(repositoryUrl, repositoryId, true, null, true, null, null)
57-
} returns artifactRepository
58-
}
59-
60-
repository.toArtifactRepository(session, repositorySystem, repositoryId) shouldBe artifactRepository
61-
}
62-
63-
"create an artifact repository with a configured proxy" {
64-
val repository = RemoteRepository.Builder("someId", "someType", "https://example.com/repo")
65-
.setProxy(Proxy("http", "proxy.example.com", 8080))
66-
.build()
67-
68-
val session = mockk<RepositorySystemSession>()
69-
val artifactRepository = mockk<org.apache.maven.artifact.repository.ArtifactRepository> {
70-
every { proxy = any() } just runs
71-
}
72-
73-
val repositorySystem = mockk<MavenRepositorySystem> {
74-
every {
75-
createRepository(any(), any(), true, null, true, null, null)
76-
} returns artifactRepository
77-
}
78-
79-
repository.toArtifactRepository(session, repositorySystem, "id") shouldBe artifactRepository
80-
81-
val slotProxy = slot<MavenProxy>()
82-
verify {
83-
artifactRepository.proxy = capture(slotProxy)
84-
}
85-
86-
with(slotProxy.captured) {
87-
host shouldBe "proxy.example.com"
88-
port shouldBe 8080
89-
protocol shouldBe "http"
90-
}
91-
}
92-
93-
"create an artifact repository with authentication" {
94-
val repository = RemoteRepository.Builder("someId", "someType", "https://example.com/repo")
95-
.setAuthentication(
96-
AuthenticationBuilder()
97-
.addUsername("scott")
98-
.addPassword("tiger".toCharArray())
99-
.addPrivateKey("privateKeyPath", "passphrase")
100-
.build()
101-
).build()
102-
103-
val session = mockk<RepositorySystemSession>()
104-
val artifactRepository = mockk<org.apache.maven.artifact.repository.ArtifactRepository> {
105-
every { authentication = any() } just runs
106-
}
107-
108-
val repositorySystem = mockk<MavenRepositorySystem> {
109-
every {
110-
createRepository(any(), any(), true, null, true, null, null)
111-
} returns artifactRepository
112-
}
113-
114-
repository.toArtifactRepository(session, repositorySystem, "id") shouldBe artifactRepository
115-
116-
val slotAuth = slot<Authentication>()
117-
verify {
118-
artifactRepository.authentication = capture(slotAuth)
119-
}
120-
121-
with(slotAuth.captured) {
122-
username shouldBe "scott"
123-
password shouldBe "tiger"
124-
privateKey shouldBe "privateKeyPath"
125-
passphrase shouldBe "passphrase"
126-
}
127-
}
128-
129-
"create an artifact repository with a configured proxy that requires authentication" {
130-
val proxyAuth = AuthenticationBuilder()
131-
.addUsername("proxyUser")
132-
.addPassword("proxyPassword".toCharArray())
133-
.build()
134-
val repository = RemoteRepository.Builder("someId", "someType", "https://example.com/repo")
135-
.setProxy(Proxy("http", "proxy.example.com", 8080, proxyAuth))
136-
.build()
137-
138-
val session = mockk<RepositorySystemSession>()
139-
val artifactRepository = mockk<org.apache.maven.artifact.repository.ArtifactRepository> {
140-
every { proxy = any() } just runs
141-
}
142-
143-
val repositorySystem = mockk<MavenRepositorySystem> {
144-
every {
145-
createRepository(any(), any(), true, null, true, null, null)
146-
} returns artifactRepository
147-
}
148-
149-
repository.toArtifactRepository(session, repositorySystem, "id") shouldBe artifactRepository
150-
151-
val slotProxy = slot<MavenProxy>()
152-
verify {
153-
artifactRepository.proxy = capture(slotProxy)
154-
}
155-
156-
with(slotProxy.captured) {
157-
userName shouldBe "proxyUser"
158-
password shouldBe "proxyPassword"
159-
}
160-
}
161-
}
162-
16329
"isTychoProject()" should {
16430
"return true if the Tycho extension is found" {
16531
val projectDir = tempdir()

0 commit comments

Comments
 (0)
Please sign in to comment.