Skip to content

Commit 4a6f8c6

Browse files
committed
Rework RewriteMavenSettingsInitializer
1 parent edcb07a commit 4a6f8c6

File tree

2 files changed

+324
-2
lines changed

2 files changed

+324
-2
lines changed

components/sbm-core/src/main/java/org/springframework/sbm/build/impl/MavenSettingsInitializer.java renamed to components/sbm-core/src/main/java/org/springframework/sbm/project/parser/RewriteMavenSettingsInitializer.java

+24-2
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,16 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
package org.springframework.sbm.build.impl;
16+
package org.springframework.sbm.project.parser;
1717

18+
import lombok.RequiredArgsConstructor;
1819
import org.openrewrite.ExecutionContext;
20+
import org.openrewrite.Parser;
1921
import org.openrewrite.maven.MavenExecutionContextView;
2022
import org.openrewrite.maven.MavenSettings;
23+
import org.springframework.core.io.Resource;
24+
import org.springframework.sbm.project.parser.MavenPasswordDecrypter;
25+
import org.springframework.sbm.testhelper.ResourceUtil;
2126
import org.springframework.stereotype.Component;
2227

2328
import java.nio.file.Files;
@@ -27,7 +32,15 @@
2732
* @author Fabian Krüger
2833
*/
2934
@Component
30-
public class MavenSettingsInitializer {
35+
@RequiredArgsConstructor
36+
public class RewriteMavenSettingsInitializer {
37+
38+
private final MavenPasswordDecrypter mavenPasswordDecrypter;
39+
40+
/**
41+
* @deprecated initialization in ExecutionoContext is done in ProjectParser
42+
*/
43+
@Deprecated(forRemoval = true)
3144
public void initializeMavenSettings(ExecutionContext executionContext) {
3245
// Read .m2/settings.xml
3346
// TODO: Add support for global Maven settings (${maven.home}/conf/settings.xml).
@@ -38,4 +51,13 @@ public void initializeMavenSettings(ExecutionContext executionContext) {
3851
mavenExecutionContextView.setMavenSettings(mavenSettings);
3952
}
4053
}
54+
55+
public MavenSettings initializeMavenSettings(ExecutionContext executionContext, Resource mavenSettingsFile, Path securitySettingsFilePath) {
56+
Parser.Input input = new Parser.Input(ResourceUtil.getPath(mavenSettingsFile), () -> ResourceUtil.getInputStream(mavenSettingsFile));
57+
MavenSettings mavenSettings = MavenSettings.parse(input, executionContext);
58+
mavenPasswordDecrypter.decryptMavenServerPasswords(mavenSettings, securitySettingsFilePath);
59+
MavenExecutionContextView.view(executionContext).setMavenSettings(mavenSettings);
60+
return mavenSettings;
61+
}
62+
4163
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,300 @@
1+
package org.springframework.sbm.project.parser;
2+
3+
import org.apache.maven.execution.MavenExecutionRequest;
4+
import org.apache.maven.execution.MavenSession;
5+
import org.apache.maven.model.*;
6+
import org.apache.maven.plugin.logging.Log;
7+
import org.apache.maven.rtinfo.RuntimeInformation;
8+
import org.apache.maven.settings.Mirror;
9+
import org.apache.maven.settings.Server;
10+
import org.apache.maven.settings.crypto.*;
11+
import org.intellij.lang.annotations.Language;
12+
import org.junit.jupiter.api.BeforeEach;
13+
import org.junit.jupiter.api.Test;
14+
import org.junit.jupiter.api.io.TempDir;
15+
import org.openrewrite.ExecutionContext;
16+
import org.openrewrite.InMemoryExecutionContext;
17+
import org.openrewrite.internal.lang.Nullable;
18+
import org.openrewrite.maven.MavenMojoProjectParser;
19+
import org.openrewrite.maven.MavenSettings;
20+
import org.openrewrite.maven.tree.MavenRepository;
21+
import org.sonatype.plexus.components.cipher.DefaultPlexusCipher;
22+
import org.sonatype.plexus.components.cipher.PlexusCipherException;
23+
import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher;
24+
import org.springframework.core.io.Resource;
25+
import org.springframework.sbm.project.TestDummyResource;
26+
import org.springframework.test.util.ReflectionTestUtils;
27+
28+
import java.io.IOException;
29+
import java.nio.file.Files;
30+
import java.nio.file.Path;
31+
import java.util.Arrays;
32+
import java.util.Collection;
33+
import java.util.List;
34+
35+
import static org.assertj.core.api.Assertions.assertThat;
36+
import static org.mockito.Mockito.*;
37+
38+
/**
39+
* Test feature parity between OpenRewrite Maven plugin settings initialization and |@link {@link RewriteMavenSettingsInitializer}.
40+
*
41+
* - {@link #initializeMavenSettings_withOpenRewriteMavenPlugin()} uses OpenRewrite Maven plugin to create {@link MavenSettings}.
42+
* - {@link #initializeMavenSettings_withRewriteMavenSettingsInitializer()} uses SBM {@link RewriteMavenSettingsInitializer} to initialize {@link MavenSettings}.
43+
*
44+
* The tests verify {@link #verifyMavenSettings(MavenSettings)} that both approaches yield the same results given same input.
45+
*
46+
* @author Fabian Krüger
47+
*/
48+
class RewriteMavenSettingsInitialierTest {
49+
50+
private final String profile1_id = "profile1";
51+
private static final Path mavenHome = Path.of("./target/.m2").toAbsolutePath().normalize();
52+
private static final Path mavenRepository = mavenHome.resolve("repository-changed");
53+
private static final String mirror1_id = "mirror1";
54+
private static final String mirror1_url = "mirror1_url";
55+
private static final String mirror1_mirrorOf = "mirror1_mirrorOf";
56+
private static final String server1_id = "server1_id";
57+
private static final String server1_username = "server1_username";
58+
private static final String server1_password = "{gY56I8DPBrwHu3dWkh+EGDqp+ppuTnBaWe9fNpdTPIw=}";
59+
private static final String server1_privateKey = "server1_privateKey";
60+
private static final String server1_passphrase = "server1_passphrase";
61+
private static final String server1_filePermissions = "server1_filePermissions";
62+
private static final String server1_directoryPermissions = "server1_directoryPermissions";
63+
private MavenSession mavenSession = mock(MavenSession.class);
64+
private SettingsDecrypter settingsDecrypter;
65+
private static final String decryptedPassword = "xxx";
66+
67+
private static final String MAVEN_SECURITY_FILE = """
68+
<settingsSecurity>
69+
<!-- Password: XXX -->
70+
<master>{H39p2LFBhRQHqKIsRiu0R/zhfke3/B4k0Wt+BZlC8mc=}</master>
71+
</settingsSecurity>
72+
""";
73+
74+
@Language("xml")
75+
private static final String MAVEN_SETTINGS_FILE = """
76+
<?xml version="1.0" encoding="UTF-8"?>
77+
<settings xsi:schemaLocation='http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd'
78+
xmlns='http://maven.apache.org/SETTINGS/1.0.0' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>
79+
<localRepository>%s</localRepository>
80+
<interactiveMode/>
81+
<offline/>
82+
<pluginGroups/>
83+
<servers>
84+
<server>
85+
<id>%s</id>
86+
<username>%s</username>
87+
<password>%s</password>
88+
<privateKey>%s</privateKey>
89+
<passphrase>%s</passphrase>
90+
<filePermissions>%s</filePermissions>
91+
<directoryPermissions>%s</directoryPermissions>
92+
<configuration></configuration>
93+
</server>
94+
</servers>
95+
<mirrors>
96+
<mirror>
97+
<id>%s</id>
98+
<url>%s</url>
99+
<mirrorOf>%s</mirrorOf>
100+
</mirror>
101+
</mirrors>
102+
<proxies/>
103+
<profiles>
104+
<profile>
105+
<id>profile1</id>
106+
<activation>
107+
<activeByDefault>true</activeByDefault>
108+
<jdk>17</jdk>
109+
</activation>
110+
</profile>
111+
</profiles>
112+
<activeProfiles>
113+
<activeProfile>profile1</activeProfile>
114+
</activeProfiles>
115+
</settings>
116+
""".formatted(
117+
mavenRepository,
118+
server1_id,
119+
server1_username,
120+
server1_password,
121+
server1_privateKey,
122+
server1_passphrase,
123+
server1_filePermissions,
124+
server1_directoryPermissions,
125+
mirror1_id,
126+
mirror1_url,
127+
mirror1_mirrorOf);
128+
private Path mavenSecurityFilePath;
129+
private Path mavenSettingsFilePath;
130+
131+
@BeforeEach
132+
void beforeEach(@TempDir Path tmpDir) {
133+
// Prepare internal classes to decrypt Server password
134+
try {
135+
// DefaultSecDispatcher reads file with security settings
136+
mavenSecurityFilePath = tmpDir.resolve("settings-security.xml");
137+
Files.writeString(mavenSecurityFilePath, MAVEN_SECURITY_FILE);
138+
mavenSettingsFilePath = tmpDir.resolve("settings.xml");
139+
Files.writeString(mavenSettingsFilePath, MAVEN_SETTINGS_FILE);
140+
141+
} catch (IOException e) {
142+
throw new RuntimeException(e);
143+
}
144+
}
145+
146+
/*
147+
* Use OpenRewrite Maven Plugin (@link MavenMojoProjectParser} to initialize settings.
148+
*/
149+
@Test
150+
void initializeMavenSettings_withOpenRewriteMavenPlugin() throws PlexusCipherException {
151+
MavenMojoProjectParser comparingParser = createMavenMojoProjectParser();
152+
153+
MavenExecutionRequest mavenExecutionRequest = mock(MavenExecutionRequest.class);
154+
when(mavenSession.getRequest()).thenReturn(mavenExecutionRequest);
155+
// Maven profiles
156+
Profile profile1 = mock(Profile.class);
157+
when(profile1.getId()).thenReturn(profile1_id);
158+
159+
Activation profile1_activation = mock(Activation.class);
160+
when(profile1_activation.isActiveByDefault()).thenReturn(true);
161+
when(profile1_activation.getJdk()).thenReturn("profile1_jdk");
162+
when(profile1.getActivation()).thenReturn(profile1_activation);
163+
164+
ActivationProperty profile1_property = mock(ActivationProperty.class);
165+
when(profile1_activation.getProperty()).thenReturn(profile1_property);
166+
when(profile1_property.getName()).thenReturn("profile1_property_name");
167+
when(profile1_property.getValue()).thenReturn("profile1_property_value");
168+
169+
Repository profile1_repository1 = mock(Repository.class);
170+
List<Repository> profile1_repositories = List.of(profile1_repository1);
171+
when(profile1.getRepositories()).thenReturn(profile1_repositories);
172+
173+
SettingsDecryptionResult decryptionResult = mock(SettingsDecryptionResult.class);
174+
Server decryptionResultServer = mock(Server.class);
175+
when(decryptionResult.getServer()).thenReturn(decryptionResultServer);
176+
when(decryptionResultServer.getPassword()).thenReturn(decryptedPassword);
177+
178+
when(mavenExecutionRequest.getProfiles()).thenReturn(List.of(profile1)); // with profiles
179+
// Active profiles
180+
when(mavenExecutionRequest.getActiveProfiles()).thenReturn(List.of(profile1_id)); // with active profiles
181+
// Mirrors
182+
Mirror mirror1 = mock(Mirror.class);
183+
when(mirror1.getId()).thenReturn(mirror1_id);
184+
when(mirror1.getMirrorOf()).thenReturn(mirror1_mirrorOf);
185+
when(mirror1.getUrl()).thenReturn(mirror1_url);
186+
verify(mirror1, never()).getLayout();
187+
188+
Mirror mirror2 = mock(Mirror.class);
189+
List<Mirror> mirrors = List.of(mirror1);
190+
191+
when(mavenExecutionRequest.getMirrors()).thenReturn(mirrors); // with mirrors
192+
// Servers
193+
194+
Server server1 = new Server();
195+
server1.setPassword(server1_password);
196+
server1.setId(server1_id);
197+
server1.setUsername(server1_username);
198+
server1.setFilePermissions(server1_filePermissions);
199+
server1.setDirectoryPermissions(server1_directoryPermissions);
200+
server1.setPassphrase(server1_passphrase);
201+
server1.setPrivateKey(server1_privateKey);
202+
List<Server> servers = List.of(server1);
203+
when(mavenExecutionRequest.getServers()).thenReturn(servers); // with Servers
204+
// repository path
205+
when(mavenExecutionRequest.getLocalRepositoryPath()).thenReturn(mavenRepository.toFile());
206+
207+
MavenSettings mavenSettings = comparingParser.buildSettings();
208+
209+
verifyMavenSettings(mavenSettings);
210+
}
211+
212+
@Test
213+
void initializeMavenSettings_withRewriteMavenSettingsInitializer() {
214+
ExecutionContext executionContext = new InMemoryExecutionContext();
215+
Resource securitySettingsFile = new TestDummyResource(mavenSecurityFilePath, MAVEN_SECURITY_FILE);
216+
Resource mavenSettingsFile = new TestDummyResource(mavenSettingsFilePath, MAVEN_SETTINGS_FILE);
217+
218+
RewriteMavenSettingsInitializer sut = new RewriteMavenSettingsInitializer(new MavenPasswordDecrypter());
219+
MavenSettings mavenSettings = sut.initializeMavenSettings(executionContext, mavenSettingsFile, mavenSecurityFilePath);
220+
221+
verifyMavenSettings(mavenSettings);
222+
}
223+
224+
private void verifyMavenSettings(MavenSettings mavenSettings) {
225+
assertThat(mavenSettings).isNotNull();
226+
227+
MavenSettings.ActiveProfiles activeProfiles = mavenSettings.getActiveProfiles();
228+
assertThat(activeProfiles.getActiveProfiles().get(0)).isEqualTo(profile1_id);
229+
230+
MavenRepository mavenLocal = mavenSettings.getMavenLocal();
231+
assertThat(mavenLocal.isKnownToExist()).isTrue();
232+
assertThat(mavenLocal.getUsername()).isNull();
233+
assertThat(mavenLocal.getPassword()).isNull();
234+
assertThat(mavenLocal.getSnapshots()).isNull();
235+
assertThat(mavenLocal.getReleases()).isNull();
236+
assertThat(mavenLocal.getUri()).isEqualTo("file://" + mavenRepository);
237+
assertThat(mavenLocal.getId()).isEqualTo("local");
238+
assertThat(mavenLocal.getDeriveMetadataIfMissing()).isNull();
239+
240+
MavenSettings.Profiles profiles = mavenSettings.getProfiles();
241+
assertThat(profiles.getProfiles()).hasSize(1);
242+
243+
assertThat(mavenSettings.getMirrors()).isNotNull();
244+
assertThat(mavenSettings.getMirrors().getMirrors()).hasSize(1);
245+
MavenSettings.Mirror mirror1 = mavenSettings.getMirrors().getMirrors().get(0);
246+
assertThat(mirror1.getId()).isEqualTo(mirror1_id);
247+
assertThat(mirror1.getUrl()).isEqualTo(mirror1_url);
248+
assertThat(mirror1.getMirrorOf()).isEqualTo(mirror1_mirrorOf);
249+
assertThat(mirror1.getReleases()).isNull();
250+
assertThat(mirror1.getSnapshots()).isNull();
251+
assertThat(countGetter(MavenSettings.Mirror.class)).isEqualTo(5);
252+
253+
254+
MavenSettings.Servers servers = mavenSettings.getServers();
255+
assertThat(servers.getServers()).hasSize(1);
256+
MavenSettings.Server server = servers.getServers().get(0);
257+
assertThat(server.getId()).isEqualTo(server1_id);
258+
assertThat(server.getUsername()).isEqualTo(server1_username);
259+
assertThat(server.getPassword()).isEqualTo(decryptedPassword);
260+
assertThat(countGetter(server.getClass())).isEqualTo(3);
261+
}
262+
263+
private long countGetter(Class<?> clazz) {
264+
long allGetter = internalGetGetter(clazz);
265+
long objectGetter = internalGetGetter(Object.class);
266+
return allGetter - objectGetter;
267+
}
268+
269+
private long internalGetGetter(Class<?> clazz) {
270+
return Arrays
271+
.stream(clazz.getMethods())
272+
.filter(m -> m.getName().startsWith("get"))
273+
.filter(m -> m.getParameterCount() == 0)
274+
.count();
275+
}
276+
277+
private MavenMojoProjectParser createMavenMojoProjectParser() throws PlexusCipherException {
278+
DefaultSecDispatcher securityDispatcher = new DefaultSecDispatcher();
279+
// hack, the cipher is required but can't be set from outside
280+
ReflectionTestUtils.setField(securityDispatcher, "_cipher", new DefaultPlexusCipher());
281+
settingsDecrypter = new DefaultSettingsDecrypter(securityDispatcher);
282+
// The file location is retrieved from env, default is ~/${user.home}/.settings-security.xml
283+
System.setProperty("settings.security", mavenSecurityFilePath.toString());
284+
285+
Log logger = mock(Log.class);
286+
Path baseDir = Path.of("./src/test/resources/rewrite-maven-plugin");
287+
boolean pomCacheEnabled = false;
288+
@Nullable String pomCacheDirectory = null;
289+
RuntimeInformation runtime = mock(RuntimeInformation.class);
290+
boolean skipMavenParsing = false;
291+
Collection<String> exclusions = List.of();
292+
Collection<String> plainTextMasks = List.of();
293+
int sizeThresholdMb = 1_000_000;
294+
295+
return new MavenMojoProjectParser(logger, baseDir, pomCacheEnabled, pomCacheDirectory, runtime,
296+
skipMavenParsing, exclusions, plainTextMasks, sizeThresholdMb, mavenSession,
297+
settingsDecrypter);
298+
}
299+
300+
}

0 commit comments

Comments
 (0)