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 @Parameter(property = "deleteStubsAfterTest", defaultValue = "true")
159 private boolean deleteStubsAfterTest;
160
161
162
163
164
165 @Parameter(property = "contractsProperties")
166 private Map<String, String> contractsProperties = new HashMap<>();
167
168
169
170
171 @Parameter(property = "convertToYaml", defaultValue = "false")
172 private boolean convertToYaml;
173
174 @Component(role = MavenResourcesFiltering.class, hint = "default")
175 private MavenResourcesFiltering mavenResourcesFiltering;
176
177
178
179
180
181 @Parameter(property = "failOnNoContracts", defaultValue = "true")
182 private boolean failOnNoContracts;
183
184
185
186
187
188 @Parameter(property = "incrementalContractStubs", defaultValue = "true")
189 private boolean incrementalContractStubs = true;
190
191 @Parameter(defaultValue = "${mojoExecution}", readonly = true, required = true)
192 private MojoExecution mojoExecution;
193
194 @Parameter(defaultValue = "${session}", readonly = true, required = true)
195 private MavenSession session;
196
197 @Override
198 public void execute() throws MojoExecutionException {
199 if (this.skip) {
200 getLog().info(String.format(
201 "Skipping Spring Cloud Contract Verifier execution: spring.cloud.contract.verifier.skip=%s",
202 this.skip));
203 return;
204 }
205 String groupId = this.project.getGroupId();
206 String artifactId = this.project.getArtifactId();
207 String version = this.project.getVersion();
208 String rootPath = "META-INF/" + groupId + "/" + artifactId + "/" + version;
209
210 ContractVerifierConfigProperties config = new ContractVerifierConfigProperties();
211 config.setExcludeBuildFolders(this.excludeBuildFolders);
212 File contractsDirectory = locationOfContracts(config);
213 contractsDirectory = contractSubfolderIfPresent(contractsDirectory);
214
215 if (this.incrementalContractStubs && !inputFilesChangeDetected(contractsDirectory, mojoExecution, session)) {
216 getLog().info("Nothing to generate - all stubs are up to date");
217 return;
218 }
219
220 File contractsDslDir = contractsDslDir(contractsDirectory);
221 LeftOverPrevention leftOverPrevention = new LeftOverPrevention(this.stubsDirectory, mojoExecution, session);
222
223 File copiedContracts = copyContracts(rootPath, config, contractsDirectory);
224 if (this.convertToYaml) {
225 contractsDslDir = copiedContracts;
226 convertBackedUpDslsToYaml(rootPath, config, contractsDirectory, contractsDslDir);
227 }
228 config.setContractsDslDir(contractsDslDir);
229 config.setStubsOutputDir(stubsOutputDir(rootPath));
230 logSetup(config, contractsDslDir);
231 RecursiveFilesConverter converter = new RecursiveFilesConverter(config.getStubsOutputDir(),
232 config.getContractsDslDir(), config.getExcludedFiles(), config.getIncludedContracts(),
233 config.isExcludeBuildFolders());
234 converter.processFiles();
235 leftOverPrevention.deleteLeftOvers();
236 }
237
238 private void convertBackedUpDslsToYaml(String rootPath, ContractVerifierConfigProperties config,
239 File contractsDirectory, File contractsDslDir) throws MojoExecutionException {
240 copyOriginals(rootPath, config, contractsDirectory);
241 ToYamlConverter.replaceContractWithYaml(contractsDslDir);
242 getLog().info("Replaced DSL files with their YAML representation at [" + contractsDslDir + "]");
243 }
244
245 private File copyOriginals(String rootPath, ContractVerifierConfigProperties config, File contractsDirectory)
246 throws MojoExecutionException {
247 File outputFolderWithOriginals = new File(this.stubsDirectory, rootPath + ORIGINAL_PATH);
248 new CopyContracts(this.project, this.mavenSession, this.mavenResourcesFiltering, config)
249 .copy(contractsDirectory, outputFolderWithOriginals);
250 return outputFolderWithOriginals;
251 }
252
253 private File copyContracts(String rootPath, ContractVerifierConfigProperties config, File contractsDirectory)
254 throws MojoExecutionException {
255 File outputFolderWithContracts = this.stubsDirectory.getPath().endsWith("contracts") ? this.stubsDirectory
256 : new File(this.stubsDirectory, rootPath + CONTRACTS_PATH);
257 new CopyContracts(this.project, this.mavenSession, this.mavenResourcesFiltering, config)
258 .copy(contractsDirectory, outputFolderWithContracts);
259 return outputFolderWithContracts;
260 }
261
262 private void logSetup(ContractVerifierConfigProperties config, File contractsDslDir) {
263 if (getLog().isDebugEnabled()) {
264 getLog().debug("The contracts dir equals [" + contractsDslDir + "]");
265 }
266 getLog().info("Converting from Spring Cloud Contract Verifier contracts to WireMock stubs mappings");
267 getLog().info(String.format(" Spring Cloud Contract Verifier contracts directory: %s",
268 config.getContractsDslDir()));
269 getLog().info(String.format("Stub Server stubs mappings directory: %s", config.getStubsOutputDir()));
270 }
271
272 private File contractSubfolderIfPresent(File contractsDirectory) {
273 File contractsSubFolder = new File(contractsDirectory, "contracts");
274 if (contractsSubFolder.exists()) {
275 if (getLog().isDebugEnabled()) {
276 getLog().debug("The subfolder [contracts] exists, will pick it as a source of contracts");
277 }
278 contractsDirectory = contractsSubFolder;
279 }
280 return contractsDirectory;
281 }
282
283 private File locationOfContracts(ContractVerifierConfigProperties config) {
284 return new MavenContractsDownloader(this.project, this.contractDependency, this.contractsPath,
285 this.contractsRepositoryUrl, this.contractsMode, getLog(), this.contractsRepositoryUsername,
286 this.contractsRepositoryPassword, this.contractsRepositoryProxyHost, this.contractsRepositoryProxyPort,
287 this.deleteStubsAfterTest, this.contractsProperties, this.failOnNoContracts)
288 .downloadAndUnpackContractsIfRequired(config, this.contractsDirectory);
289 }
290
291 private File stubsOutputDir(String rootPath) {
292 return isInsideProject() ? new File(this.stubsDirectory, rootPath + MAPPINGS_PATH) : this.destination;
293 }
294
295 private File contractsDslDir(File contractsDirectory) {
296 return isInsideProject() ? contractsDirectory : this.source;
297 }
298
299 private boolean isInsideProject() {
300 return this.mavenSession.getRequest().isProjectPresent();
301 }
302
303 }