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.ArrayList;
21 import java.util.Arrays;
22 import java.util.List;
23
24 import org.apache.maven.execution.MavenSession;
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.plugin.MojoFailureException;
29 import org.apache.maven.plugins.annotations.Component;
30 import org.apache.maven.plugins.annotations.LifecyclePhase;
31 import org.apache.maven.plugins.annotations.Mojo;
32 import org.apache.maven.plugins.annotations.Parameter;
33 import org.apache.maven.project.MavenProject;
34 import org.apache.maven.project.MavenProjectHelper;
35 import org.codehaus.plexus.archiver.Archiver;
36 import org.codehaus.plexus.archiver.jar.JarArchiver;
37
38 import static org.springframework.cloud.contract.maven.verifier.ChangeDetector.inputFilesChangeDetected;
39
40
41
42
43
44
45
46 @Mojo(name = "generateStubs", defaultPhase = LifecyclePhase.PACKAGE, requiresProject = true)
47 public class GenerateStubsMojo extends AbstractMojo {
48
49 @Parameter(defaultValue = "${project.build.directory}", readonly = true, required = true)
50 private File projectBuildDirectory;
51
52 @Parameter(defaultValue = "${project.build.finalName}", readonly = true, required = true)
53 private String projectFinalName;
54
55 @Parameter(property = "stubsDirectory", defaultValue = "${project.build.directory}/stubs")
56 private File outputDirectory;
57
58
59
60
61 @Parameter(property = "spring.cloud.contract.verifier.skip", defaultValue = "false")
62 private boolean skip;
63
64
65
66
67 @Parameter(property = "spring.cloud.contract.verifier.jar.skip", defaultValue = "false")
68 private boolean jarSkip;
69
70 @Component
71 private MavenProjectHelper projectHelper;
72
73
74
75
76 @Parameter
77 private String[] excludedFiles;
78
79 @Parameter(defaultValue = "${project}", readonly = true)
80 private MavenProject project;
81
82 @Component(role = Archiver.class, hint = "jar")
83 private JarArchiver archiver;
84
85 @Parameter(defaultValue = "stubs")
86 private String classifier;
87
88
89
90
91
92 @Parameter(property = "incrementalContractStubsJar", defaultValue = "true")
93 private boolean incrementalContractStubsJar = true;
94
95 @Parameter(defaultValue = "${mojoExecution}", readonly = true, required = true)
96 private MojoExecution mojoExecution;
97
98 @Parameter(defaultValue = "${session}", readonly = true, required = true)
99 private MavenSession session;
100
101
102
103
104
105 @Parameter(property = "failOnNoContracts", defaultValue = "true")
106 private boolean failOnNoContracts;
107
108 public void execute() throws MojoExecutionException, MojoFailureException {
109 if (this.skip || this.jarSkip) {
110 getLog().info("Skipping Spring Cloud Contract Verifier execution: spring.cloud.contract.verifier.skip="
111 + this.skip + ", spring.cloud.contract.verifier.jar.skip=" + this.jarSkip);
112 return;
113 }
114 else if (stubsOutputMissing(this.outputDirectory) && !this.failOnNoContracts) {
115 getLog().warn(
116 "The stubs output directory is missing, the flag to fail on no stubs if off - will continue without throwing an exception");
117 return;
118 }
119 else if (stubsOutputMissing(this.outputDirectory) && this.failOnNoContracts) {
120 throw new MojoExecutionException("Stubs could not be found: [" + this.outputDirectory.getAbsolutePath()
121 + "] .\nPlease make sure that spring-cloud-contract:convert was invoked");
122 }
123 if (this.incrementalContractStubsJar && !inputFilesChangeDetected(outputDirectory, mojoExecution, session)) {
124 getLog().info("Nothing to generate - stubs jar is up to date");
125 return;
126 }
127 File stubsJarFile = createStubJar(this.outputDirectory);
128 this.projectHelper.attachArtifact(this.project, "jar", this.classifier, stubsJarFile);
129 }
130
131 private File createStubJar(File stubsOutputDir) throws MojoFailureException, MojoExecutionException {
132 if (!stubsOutputDir.exists()) {
133 throw new MojoExecutionException("Stubs could not be found: [" + stubsOutputDir.getAbsolutePath()
134 + "] .\nPlease make sure that spring-cloud-contract:convert was invoked");
135 }
136 String stubArchiveName = this.projectFinalName + "-" + this.classifier + ".jar";
137 File stubsJarFile = new File(this.projectBuildDirectory, stubArchiveName);
138 String[] excludes = excludes();
139 getLog().info(
140 "Files matching this pattern will be excluded from " + "stubs generation " + Arrays.toString(excludes));
141 try {
142 this.archiver.addDirectory(stubsOutputDir, new String[] { "**/*.*" },
143 excludedFilesEmpty() ? new String[0] : this.excludedFiles);
144 this.archiver.setCompress(true);
145 this.archiver.setDestFile(stubsJarFile);
146 this.archiver.addConfiguredManifest(ManifestCreator.createManifest(this.project));
147 this.archiver.createArchive();
148 }
149 catch (Exception e) {
150 throw new MojoFailureException("Exception while packaging " + this.classifier + " jar.", e);
151 }
152 return stubsJarFile;
153 }
154
155 private boolean stubsOutputMissing(File stubsOutputDir) {
156 return !stubsOutputDir.exists();
157 }
158
159 private String[] excludes() {
160 List<String> excludes = new ArrayList<>();
161 if (!excludedFilesEmpty()) {
162 excludes.addAll(Arrays.asList(this.excludedFiles));
163 }
164 String[] array = new String[excludes.size()];
165 array = excludes.toArray(array);
166 return array;
167 }
168
169 private boolean excludedFilesEmpty() {
170 return this.excludedFiles == null || this.excludedFiles.length == 0;
171 }
172
173 }