View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.rat.mp;
20  
21  import java.io.ByteArrayOutputStream;
22  import java.io.File;
23  import java.nio.file.Files;
24  import java.nio.file.Paths;
25  
26  import org.apache.commons.lang3.StringUtils;
27  import org.apache.maven.plugin.MojoExecutionException;
28  import org.apache.maven.plugin.MojoFailureException;
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.rat.Defaults;
33  import org.apache.rat.ReportConfiguration;
34  import org.apache.rat.Reporter;
35  import org.apache.rat.config.AddLicenseHeaders;
36  import org.apache.rat.license.LicenseSetFactory.LicenseFilter;
37  import org.apache.rat.report.claim.ClaimStatistic;
38  
39  /**
40   * Run Rat to perform a violation check.
41   */
42  @Mojo(name = "check", defaultPhase = LifecyclePhase.VALIDATE, threadSafe = true)
43  public class RatCheckMojo extends AbstractRatMojo {
44      /**
45       * Where to store the report.
46       */
47      @Parameter(property = "rat.outputFile", defaultValue = "${project.build.directory}/rat.txt")
48      private File reportFile;
49  
50      @Parameter(property = "rat.scanHiddenDirectories", defaultValue = "false")
51      private boolean scanHiddenDirectories;
52  
53      /**
54       * Output style of the report. Use "plain" (the default) for a plain text report
55       * or "xml" for the raw XML report. Alternatively you can give the path of an
56       * XSL transformation that will be applied on the raw XML to produce the report
57       * written to the output file.
58       */
59      @Parameter(property = "rat.outputStyle", defaultValue = "plain")
60      private String reportStyle;
61  
62      /**
63       * Maximum number of files with unapproved licenses.
64       */
65      @Parameter(property = "rat.numUnapprovedLicenses", defaultValue = "0")
66      private int numUnapprovedLicenses;
67  
68      /**
69       * Whether to add license headers; possible values are {@code forced},
70       * {@code true}, and {@code false} (default).
71       */
72      @Parameter(property = "rat.addLicenseHeaders", defaultValue = "false")
73      private String addLicenseHeaders;
74  
75      /**
76       * Copyright message to add to license headers. This option is ignored, unless
77       * {@code addLicenseHeaders} is set to {@code true}, or {@code forced}.
78       */
79      @Parameter(property = "rat.copyrightMessage")
80      private String copyrightMessage;
81  
82      /**
83       * Will ignore rat errors and display a log message if any. Its use is NOT
84       * RECOMMENDED, but quite convenient on occasion.
85       *
86       * @since 0.9
87       */
88      @Parameter(property = "rat.ignoreErrors", defaultValue = "false")
89      private boolean ignoreErrors;
90  
91      /**
92       * Whether to output the names of files that have unapproved licenses to the
93       * console. Defaults to {@code true} to ease builds in containers where you are
94       * unable to access rat.txt easily.
95       *
96       * @since 0.12
97       */
98      @Parameter(property = "rat.consoleOutput", defaultValue = "true")
99      private boolean consoleOutput;
100 
101     /**
102      * Invoked by Maven to execute the Mojo.
103      *
104      * @throws MojoFailureException An error in the plugin configuration was
105      * detected.
106      * @throws MojoExecutionException Another error occurred while executing the
107      * plugin.
108      */
109     @Override
110     public void execute() throws MojoExecutionException, MojoFailureException {
111         if (skip) {
112             getLog().info("RAT will not execute since it is configured to be skipped via system property 'rat.skip'.");
113             return;
114         }
115         ReportConfiguration config = getConfiguration();
116         logLicenses(config.getLicenses(LicenseFilter.all));
117         final File parent = reportFile.getParentFile();
118         if (!parent.mkdirs() && !parent.isDirectory()) {
119             throw new MojoExecutionException("Could not create report parent directory " + parent);
120         }
121 
122         try {
123             final ClaimStatistic report = Reporter.report(config);
124             check(report, config);
125         } catch (MojoExecutionException | MojoFailureException e) {
126             throw e;
127         } catch (Exception e) {
128             throw new MojoExecutionException(e.getMessage(), e);
129         }
130     }
131 
132     protected void check(ClaimStatistic statistics, ReportConfiguration config) throws MojoFailureException {
133         if (numUnapprovedLicenses > 0) {
134             getLog().info("You requested to accept " + numUnapprovedLicenses + " files with unapproved licenses.");
135         }
136 
137         int numApproved = statistics.getNumApproved();
138         getLog().info("Rat check: Summary over all files. Unapproved: " + statistics.getNumUnApproved() + //
139                 ", unknown: " + statistics.getNumUnknown() + //
140                 ", generated: " + statistics.getNumGenerated() + //
141                 ", approved: " + numApproved + //
142                 (numApproved > 0 ? " licenses." : " license."));
143 
144         if (numUnapprovedLicenses < statistics.getNumUnApproved()) {
145             if (consoleOutput) {
146                 try {
147                     config.setStyleSheet(Defaults.getUnapprovedLicensesStyleSheet());
148                     ByteArrayOutputStream baos = new ByteArrayOutputStream();
149                     config.setOut(()->baos);
150                     Reporter.report(config);
151                     getLog().warn(baos.toString());
152                 } catch (Exception e) {
153                     getLog().warn("Unable to print the files with unapproved licenses to the console.");
154                 }
155             }
156 
157             final String seeReport = " See RAT report in: " + reportFile;
158             if (!ignoreErrors) {
159                 throw new RatCheckException(
160                         "Too many files with unapproved license: " + statistics.getNumUnApproved() + seeReport);
161             }
162             getLog().warn(
163                     "Rat check: " + statistics.getNumUnApproved() + " files with unapproved licenses." + seeReport);
164         }
165     }
166 
167     @Override
168     protected ReportConfiguration getConfiguration() throws MojoExecutionException {
169         final ReportConfiguration configuration = super.getConfiguration();
170         if (StringUtils.isNotBlank(addLicenseHeaders)) {
171             configuration.setAddLicenseHeaders(AddLicenseHeaders.valueOf(addLicenseHeaders.toUpperCase()));
172         }
173         if (StringUtils.isNotBlank(copyrightMessage)) {
174             configuration.setCopyrightMessage(copyrightMessage);
175         }
176         if (scanHiddenDirectories) {
177             configuration.setDirectoryFilter(null);
178         }
179         if (reportFile != null) {
180             if (!reportFile.exists()) {
181                 reportFile.getParentFile().mkdirs();
182             }
183             configuration.setOut(reportFile);
184         }
185         if (StringUtils.isNotBlank(reportStyle)) {
186             if ("xml".equalsIgnoreCase(reportStyle)) {
187                 configuration.setStyleReport(false);
188             } else {
189                 configuration.setStyleReport(true);
190                 if (!"plain".equalsIgnoreCase(reportStyle)) {
191                     configuration.setStyleSheet(() -> Files.newInputStream(Paths.get(reportStyle)));
192                 }
193             }
194         }
195         return configuration;
196     }
197 }