1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.cloud.contract.maven.verifier;
18
19 import java.io.File;
20 import java.util.HashMap;
21 import java.util.Map;
22
23 import org.apache.maven.execution.MavenSession;
24 import org.apache.maven.model.Dependency;
25 import org.apache.maven.plugin.AbstractMojo;
26 import org.apache.maven.plugin.MojoExecution;
27 import org.apache.maven.plugin.MojoExecutionException;
28 import org.apache.maven.plugins.annotations.Component;
29 import org.apache.maven.plugins.annotations.LifecyclePhase;
30 import org.apache.maven.plugins.annotations.Mojo;
31 import org.apache.maven.plugins.annotations.Parameter;
32 import org.apache.maven.project.MavenProject;
33 import org.apache.maven.shared.filtering.MavenResourcesFiltering;
34 import org.eclipse.aether.RepositorySystemSession;
35
36 import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties;
37 import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties;
38 import org.springframework.cloud.contract.verifier.converter.RecursiveFilesConverter;
39 import org.springframework.cloud.contract.verifier.converter.ToYamlConverter;
40
41 import static org.springframework.cloud.contract.maven.verifier.ChangeDetector.inputFilesChangeDetected;
42
43
44
45
46
47
48
49
50
51 @Mojo(name = "convert", requiresProject = false, defaultPhase = LifecyclePhase.PROCESS_TEST_RESOURCES)
52 public class ConvertMojo extends AbstractMojo {
53
54 static final String DEFAULT_STUBS_DIR = "${project.build.directory}/stubs/";
55 static final String MAPPINGS_PATH = "/mappings";
56 static final String CONTRACTS_PATH = "/contracts";
57 static final String ORIGINAL_PATH = "/original";
58
59 @Parameter(defaultValue = "${repositorySystemSession}", readonly = true)
60 private RepositorySystemSession repoSession;
61
62
63
64
65
66 @Parameter(property = "spring.cloud.contract.verifier.contractsDirectory",
67 defaultValue = "${project.basedir}/src/test/resources/contracts")
68 private File contractsDirectory;
69
70
71
72
73
74 @Parameter(defaultValue = DEFAULT_STUBS_DIR)
75 private File stubsDirectory;
76
77
78
79
80
81
82 @Parameter(property = "contractsDirectory", defaultValue = "${basedir}")
83 private File source;
84
85 @Parameter(property = "stubsDirectory", defaultValue = "${basedir}")
86 private File destination;
87
88 @Parameter(property = "spring.cloud.contract.verifier.skip", defaultValue = "false")
89 private boolean skip;
90
91 @Parameter(defaultValue = "${session}", readonly = true)
92 private MavenSession mavenSession;
93
94 @Parameter(defaultValue = "${project}", readonly = true)
95 private MavenProject project;
96
97
98
99
100
101
102 @Parameter(property = "contractsRepositoryUrl")
103 private String contractsRepositoryUrl;
104
105 @Parameter(property = "contractDependency")
106 private Dependency contractDependency;
107
108
109
110
111
112
113
114 @Parameter(property = "contractsPath")
115 private String contractsPath;
116
117
118
119
120 @Parameter(property = "contractsMode", defaultValue = "CLASSPATH")
121 private StubRunnerProperties.StubsMode contractsMode;
122
123
124
125
126
127 @Parameter(property = "excludeBuildFolders", defaultValue = "false")
128 private boolean excludeBuildFolders;
129
130
131
132
133 @Parameter(property = "contractsRepositoryUsername")
134 private String contractsRepositoryUsername;
135
136
137
138
139 @Parameter(property = "contractsRepositoryPassword")
140 private String contractsRepositoryPassword;
141
142
143
144
145 @Parameter(property = "contractsRepositoryProxyHost")
146 private String contractsRepositoryProxyHost;
147
148
149
150
151 @Parameter(property = "contractsRepositoryProxyPort")
152 private Integer contractsRepositoryProxyPort;
153
154
155
156
157
158
159 @Parameter(property = "contractsSnapshotCheckSkip", defaultValue = "false")
160 @Deprecated
161 private boolean contractsSnapshotCheckSkip;
162
163
164
165
166
167 @Parameter(property = "deleteStubsAfterTest", defaultValue = "true")
168 private boolean deleteStubsAfterTest;
169
170
171
172
173
174 @Parameter(property = "contractsProperties")
175 private Map<String, String> contractsProperties = new HashMap<>();
176
177
178
179
180 @Parameter(property = "convertToYaml", defaultValue = "false")
181 private boolean convertToYaml;
182
183 @Component(role = MavenResourcesFiltering.class, hint = "default")
184 private MavenResourcesFiltering mavenResourcesFiltering;
185
186
187
188
189
190 @Parameter(property = "failOnNoContracts", defaultValue = "true")
191 private boolean failOnNoContracts;
192
193
194
195
196
197 @Parameter(property = "incrementalContractStubs", defaultValue = "true")
198 private boolean incrementalContractStubs = true;
199
200 @Parameter(defaultValue = "${mojoExecution}", readonly = true, required = true)
201 private MojoExecution mojoExecution;
202
203 @Parameter(defaultValue = "${session}", readonly = true, required = true)
204 private MavenSession session;
205
206 @Override
207 public void execute() throws MojoExecutionException {
208 if (this.skip) {
209 getLog().info(String.format(
210 "Skipping Spring Cloud Contract Verifier execution: spring.cloud.contract.verifier.skip=%s",
211 this.skip));
212 return;
213 }
214 String groupId = this.project.getGroupId();
215 String artifactId = this.project.getArtifactId();
216 String version = this.project.getVersion();
217 String rootPath = "META-INF/" + groupId + "/" + artifactId + "/" + version;
218
219 ContractVerifierConfigProperties config = new ContractVerifierConfigProperties();
220 config.setExcludeBuildFolders(this.excludeBuildFolders);
221 File contractsDirectory = locationOfContracts(config);
222 contractsDirectory = contractSubfolderIfPresent(contractsDirectory);
223
224 if (this.incrementalContractStubs && !inputFilesChangeDetected(contractsDirectory, mojoExecution, session)) {
225 getLog().info("Nothing to generate - all stubs are up to date");
226 return;
227 }
228
229 File contractsDslDir = contractsDslDir(contractsDirectory);
230 LeftOverPrevention leftOverPrevention = new LeftOverPrevention(this.stubsDirectory, mojoExecution, session);
231
232 File copiedContracts = copyContracts(rootPath, config, contractsDirectory);
233 if (this.convertToYaml) {
234 contractsDslDir = copiedContracts;
235 convertBackedUpDslsToYaml(rootPath, config, contractsDirectory, contractsDslDir);
236 }
237 config.setContractsDslDir(contractsDslDir);
238 config.setStubsOutputDir(stubsOutputDir(rootPath));
239 logSetup(config, contractsDslDir);
240 RecursiveFilesConverter converter = new RecursiveFilesConverter(config.getStubsOutputDir(),
241 config.getContractsDslDir(), config.getExcludedFiles(), config.getIncludedContracts(),
242 config.isExcludeBuildFolders());
243 converter.processFiles();
244 leftOverPrevention.deleteLeftOvers();
245 }
246
247 private void convertBackedUpDslsToYaml(String rootPath, ContractVerifierConfigProperties config,
248 File contractsDirectory, File contractsDslDir) throws MojoExecutionException {
249 copyOriginals(rootPath, config, contractsDirectory);
250 ToYamlConverter.replaceContractWithYaml(contractsDslDir);
251 getLog().info("Replaced DSL files with their YAML representation at [" + contractsDslDir + "]");
252 }
253
254 private File copyOriginals(String rootPath, ContractVerifierConfigProperties config, File contractsDirectory)
255 throws MojoExecutionException {
256 File outputFolderWithOriginals = new File(this.stubsDirectory, rootPath + ORIGINAL_PATH);
257 new CopyContracts(this.project, this.mavenSession, this.mavenResourcesFiltering, config)
258 .copy(contractsDirectory, outputFolderWithOriginals);
259 return outputFolderWithOriginals;
260 }
261
262 private File copyContracts(String rootPath, ContractVerifierConfigProperties config, File contractsDirectory)
263 throws MojoExecutionException {
264 File outputFolderWithContracts = this.stubsDirectory.getPath().endsWith("contracts") ? this.stubsDirectory
265 : new File(this.stubsDirectory, rootPath + CONTRACTS_PATH);
266 new CopyContracts(this.project, this.mavenSession, this.mavenResourcesFiltering, config)
267 .copy(contractsDirectory, outputFolderWithContracts);
268 return outputFolderWithContracts;
269 }
270
271 private void logSetup(ContractVerifierConfigProperties config, File contractsDslDir) {
272 if (getLog().isDebugEnabled()) {
273 getLog().debug("The contracts dir equals [" + contractsDslDir + "]");
274 }
275 getLog().info("Converting from Spring Cloud Contract Verifier contracts to WireMock stubs mappings");
276 getLog().info(String.format(" Spring Cloud Contract Verifier contracts directory: %s",
277 config.getContractsDslDir()));
278 getLog().info(String.format("Stub Server stubs mappings directory: %s", config.getStubsOutputDir()));
279 }
280
281 private File contractSubfolderIfPresent(File contractsDirectory) {
282 File contractsSubFolder = new File(contractsDirectory, "contracts");
283 if (contractsSubFolder.exists()) {
284 if (getLog().isDebugEnabled()) {
285 getLog().debug("The subfolder [contracts] exists, will pick it as a source of contracts");
286 }
287 contractsDirectory = contractsSubFolder;
288 }
289 return contractsDirectory;
290 }
291
292 private File locationOfContracts(ContractVerifierConfigProperties config) {
293 return new MavenContractsDownloader(this.project, this.contractDependency, this.contractsPath,
294 this.contractsRepositoryUrl, this.contractsMode, getLog(), this.contractsRepositoryUsername,
295 this.contractsRepositoryPassword, this.contractsRepositoryProxyHost, this.contractsRepositoryProxyPort,
296 this.deleteStubsAfterTest, this.contractsProperties, this.failOnNoContracts)
297 .downloadAndUnpackContractsIfRequired(config, this.contractsDirectory);
298 }
299
300 private File stubsOutputDir(String rootPath) {
301 return isInsideProject() ? new File(this.stubsDirectory, rootPath + MAPPINGS_PATH) : this.destination;
302 }
303
304 private File contractsDslDir(File contractsDirectory) {
305 return isInsideProject() ? contractsDirectory : this.source;
306 }
307
308 private boolean isInsideProject() {
309 return this.mavenSession.getRequest().isProjectPresent();
310 }
311
312 }