FYI - I have taken some code from Apache Kafka that runs RAT checks as a gradle plugin.
We can now run this as part of the CI build. It generates a report in HTML format we can publish as well. Please review and let me know if you have feedback. Cheers, Antoine > Begin forwarded message: > > From: [email protected] > Subject: [incubator-tuweni] branch master updated: Integrate rat to the build > Date: June 3, 2019 at 10:26:36 AM PDT > To: "[email protected]" <[email protected]> > Reply-To: [email protected] > > This is an automated email from the ASF dual-hosted git repository. > > toulmean pushed a commit to branch master > in repository https://gitbox.apache.org/repos/asf/incubator-tuweni.git > > > The following commit(s) were added to refs/heads/master by this push: > new e66bb9e Integrate rat to the build > e66bb9e is described below > > commit e66bb9ee31ff8168552abff076743abd1e9308f7 > Author: Antoine Toulme <[email protected]> > AuthorDate: Mon Jun 3 10:26:23 2019 -0700 > > Integrate rat to the build > --- > .rat-excludes | 19 --- > build.gradle | 44 ++++++- > gradle/rat.gradle | 122 +++++++++++++++++++ > gradle/resources/rat-output-to-html.xsl | 206 ++++++++++++++++++++++++++++++++ > 4 files changed, 371 insertions(+), 20 deletions(-) > > diff --git a/.rat-excludes b/.rat-excludes > deleted file mode 100644 > index d130894..0000000 > --- a/.rat-excludes > +++ /dev/null > @@ -1,19 +0,0 @@ > -.*\.asc > -\w+/out/.* > -eth-reference-tests > -build > -\..* > -gradlew.bat > -gradlew > -toml/src/test/resources/.* > -.gitattributes > -test1.txt > -test2.txt > -test3.yaml > -.*\.kotlin_module > -example-v0.4.0.toml > -hard_example.toml > -toml-v0.5.0-spec-example.toml > -test.txt > -resourceresolver-test.jar > -gradle-wrapper.jar > \ No newline at end of file > diff --git a/build.gradle b/build.gradle > index a354d9d..eeb13c8 100644 > --- a/build.gradle > +++ b/build.gradle > @@ -10,6 +10,7 @@ > * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either > express or implied. See the License for the > * specific language governing permissions and limitations under the License. > */ > +import org.ajoberstar.grgit.Grgit > import java.time.Instant > import java.time.ZoneId > import java.time.format.DateTimeFormatter > @@ -20,6 +21,10 @@ import net.ltgt.gradle.errorprone.CheckSeverity > buildscript { > repositories { jcenter() // jcenter > } > + > + dependencies { > + classpath "org.ajoberstar.grgit:grgit-core:3.1.1" > + } > } > > plugins { > @@ -83,7 +88,44 @@ gradle.startParameter.taskNames.each { > } > gradle.startParameter.taskNames = expandedTaskList.flatten() > > -apply from: file('wrapper.gradle') > +apply from: "${rootDir}/wrapper.gradle" > + > +////// > +// RAT checks > + > +if (file('.git').exists()) { > + apply from: "${rootDir}/gradle/rat.gradle" > + rat { > + // Exclude everything under the directory that git should be ignoring > via .gitignore or that isn't checked in. These > + // restrict us only to files that are checked in or are staged. > + def repo = Grgit.open(currentDir: project.getRootDir()) > + excludes = new ArrayList<String>(repo.clean(ignore: false, directories: > true, dryRun: true)) > + // And some of the files that we have checked in should also be excluded > from this check > + excludes.addAll([ > + '.*\\.asc', > + '\\w+/out/.*', > + 'eth-reference-tests/**', > + 'build', > + '.circleci/*', > + '.editorconfig', > + '.idea/**', > + 'gradlew.bat', > + 'gradlew', > + 'io/src/test/resources/org/apache/tuweni/io/file/**', > + 'toml/src/test/resources/**', > + '.gitattributes', > + 'test1.txt', > + 'test2.txt', > + 'test3.yaml', > + '.*\\.kotlin_module', > + 'example-v0.4.0.toml', > + 'hard_example.toml', > + 'toml-v0.5.0-spec-example.toml', > + 'test.txt', > + 'resourceresolver-test.jar' > + ]) > + } > +} > > ////// > // Gradle script formatting > diff --git a/gradle/rat.gradle b/gradle/rat.gradle > new file mode 100644 > index 0000000..f55daba > --- /dev/null > +++ b/gradle/rat.gradle > @@ -0,0 +1,122 @@ > +/* > + * Licensed to the Apache Software Foundation (ASF) under one > + * or more contributor license agreements. See the NOTICE file > + * distributed with this work for additional information > + * regarding copyright ownership. The ASF licenses this file > + * to you under the Apache License, Version 2.0 (the > + * "License"); you may not use this file except in compliance > + * with the License. You may obtain a copy of the License at > + * > + * http://www.apache.org/licenses/LICENSE-2.0 > + * > + * Unless required by applicable law or agreed to in writing, > + * software distributed under the License is distributed on an > + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY > + * KIND, either express or implied. See the License for the > + * specific language governing permissions and limitations > + * under the License. > + */ > + > +/** > + * Copied from the Apache Kafka project. See > https://github.com/apache/kafka/blob/trunk/gradle/rat.gradle. > + */ > + > +import org.gradle.api.internal.project.IsolatedAntBuilder > + > +apply plugin: RatPlugin > + > +class RatTask extends DefaultTask { > + @Input > + List<String> excludes > + > + def reportDir = project.file('build/rat') > + def stylesheet = > project.file('gradle/resources/rat-output-to-html.xsl').getAbsolutePath() > + def xmlReport = new File(reportDir, 'rat-report.xml') > + def htmlReport = new File(reportDir, 'rat-report.html') > + > + def generateXmlReport(File reportDir) { > + def antBuilder = services.get(IsolatedAntBuilder) > + def ratClasspath = project.configurations.rat > + def projectPath = project.getRootDir().getAbsolutePath() > + antBuilder.withClasspath(ratClasspath).execute { > + ant.taskdef(resource: 'org/apache/rat/anttasks/antlib.xml') > + ant.report(format: 'xml', reportFile: xmlReport) { > + fileset(dir: projectPath) { > + patternset { > + excludes.each { > + exclude(name: it) > + } > + } > + } > + } > + } > + } > + > + def printUnknownFiles() { > + def ratXml = new XmlParser().parse(xmlReport) > + def unknownLicenses = 0 > + ratXml.resource.each { resource -> > + if (resource.'license-approval'.@name[0] == "false") { > + println('Unknown license: ' + resource.@name) > + unknownLicenses++ > + } > + } > + if (unknownLicenses > 0) { > + throw new GradleException("Found " + unknownLicenses + " files > with " + > + "unknown licenses.") > + } > + } > + > + def generateHtmlReport() { > + def antBuilder = services.get(IsolatedAntBuilder) > + def ratClasspath = project.configurations.rat > + antBuilder.withClasspath(ratClasspath).execute { > + ant.xslt( > + in: xmlReport, > + style: stylesheet, > + out: htmlReport, > + classpath: ratClasspath) > + } > + println('Rat report: ' + htmlReport) > + } > + > + @TaskAction > + def rat() { > + if (!reportDir.exists()) { > + reportDir.mkdirs() > + } > + def origEncoding = System.getProperty("file.encoding") > + try { > + System.setProperty("file.encoding", "UTF-8") //affects the > output of the ant rat task > + generateXmlReport(reportDir) > + printUnknownFiles() > + generateHtmlReport() > + } finally { > + System.setProperty("file.encoding", origEncoding) > + } > + } > +} > + > +class RatPlugin implements Plugin<Project> { > + void apply(Project project) { > + configureDependencies(project) > + project.plugins.apply(JavaPlugin); > + Task ratTask = project.task("rat", > + type: RatTask, > + group: 'Build', > + description: 'Runs Apache Rat checks.') > + project.tasks[JavaPlugin.TEST_TASK_NAME].dependsOn ratTask > + } > + > + void configureDependencies(final Project project) { > + project.configurations { > + rat > + } > + project.repositories { > + mavenCentral() > + } > + project.dependencies { > + rat 'org.apache.rat:apache-rat-tasks:0.13' > + } > + } > +} > \ No newline at end of file > diff --git a/gradle/resources/rat-output-to-html.xsl > b/gradle/resources/rat-output-to-html.xsl > new file mode 100644 > index 0000000..815f46b > --- /dev/null > +++ b/gradle/resources/rat-output-to-html.xsl > @@ -0,0 +1,206 @@ > +<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > version="2.0"> > + > + <!--*********************************************************** > + * > + * Licensed to the Apache Software Foundation (ASF) under one > + * or more contributor license agreements. See the NOTICE file > + * distributed with this work for additional information > + * regarding copyright ownership. The ASF licenses this file > + * to you under the Apache License, Version 2.0 (the > + * "License"); you may not use this file except in compliance > + * with the License. You may obtain a copy of the License at > + * > + * http://www.apache.org/licenses/LICENSE-2.0 > + * > + * Unless required by applicable law or agreed to in writing, > + * software distributed under the License is distributed on an > + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY > + * KIND, either express or implied. See the License for the > + * specific language governing permissions and limitations > + * under the License. > + * > + ***********************************************************--> > + > + <!-- This style sheet converts any rat-report.xml file. --> > + > + <xsl:template match="/"> > + > + <html> > + <head> > + <meta http-equiv="Content-Type" content="text/html; > charset=UTF-8"/> > + <style type="text/css"> > + <!-- > + body {margin-top: 0px;font-size: 0.8em;background-color: > #F9F7ED;} > + > + h1 {color:red;} > + h2 {color:blue;} > + h3 {color:green;} > + h4 {color:orange;} > + > + /* Table Design */ > + > + table,tr,td > {text-align:center;font-weight:bold;border:1px solid #000;} > + caption {color:blue;text-align:left;} > + .notes, .binaries, .archives, .standards {width:25%;} > + .notes {background:#D7EDEE;} > + .binaries {background:#D0F2F4;} > + .archives {background:#ABE7E9;} > + .standards {background:#A0F0F4;} > + .licenced, .generated {width:50%;} > + .licenced {background:#C6EBDD;} > + .generated {background:#ABE9D2;} > + .java_note {background:#D6EBC6;} > + .generated_note {background:#C9E7A9;} > + .unknown {width:100%;background:#E92020;} > + .unknown-zero {color:#00CC00;} > + .center{text-align:center;margin:0 auto;} > + --> > + </style> > + </head> > + <body> > + <xsl:apply-templates/> > + <xsl:call-template name="generated"/> > + </body> > + </html> > + </xsl:template> > + > + <xsl:template match="rat-report"> > + > + <h1>Rat Report</h1> > + <p>This HTML version (yes, it is!) is generated from the RAT xml > reports using Saxon9B. All the outputs required are displayed below, similar > to the .txt version. > + This is obviously a work in progress; and a prettier, easier to > read and manage version will be available soon</p> > + <div class="center"> > + <table id="rat-reports summary" cellspacing="0" summary="A > snapshot summary of this rat report"> > + <caption> > + Table 1: A snapshot summary of this rat report. > + </caption> > + <tr> > + <td colspan="1" class="notes">Notes: <xsl:value-of > select="count(descendant::type[attribute::name="notice"])"/></td> > + <td colspan="1" class="binaries">Binaries: <xsl:value-of > select="count(descendant::type[attribute::name="binary"])"/></td> > + <td colspan="1" class="archives">Archives: <xsl:value-of > select="count(descendant::type[attribute::name="archive"])"/></td> > + <td colspan="1" class="standards">Standards: > <xsl:value-of > select="count(descendant::type[attribute::name="standard"])"/></td> > + </tr> > + <tr> > + <td colspan="2" class="licenced">Apache Licensed: > <xsl:value-of select="count(descendant::header-type[attribute::name="AL > "])"/></td> > + <td colspan="2" class="generated">Generated Documents: > <xsl:value-of select="count(descendant::header-type[attribute::name="GEN > "])"/></td> > + </tr> > + <tr> > + <td colspan="2" class="java_note">Note: JavaDocs are > generated and so license header is optional</td> > + <td colspan="2" class="generated_note">Note: Generated > files do not require license headers</td> > + </tr> > + <tr> > + <xsl:choose> > + <xsl:when > test="count(descendant::header-type[attribute::name="?????"]) > > 0"> > + <td colspan="4" class="unknown"><xsl:value-of > select="count(descendant::header-type[attribute::name="?????"])"/> > Unknown Licenses - or files without a license.</td> > + </xsl:when> > + <xsl:otherwise> > + <td colspan="4" > class="unknown-zero"><xsl:value-of > select="count(descendant::header-type[attribute::name="?????"])"/> > Unknown Licenses - or files without a license.</td> > + </xsl:otherwise> > + </xsl:choose> > + </tr> > + </table> > + </div> > + <hr/> > + <h3>Unapproved Licenses:</h3> > + > + <xsl:for-each > select="descendant::resource[license-approval/@name="false"]"> > + <xsl:text> </xsl:text> > + <xsl:value-of select="@name"/><br/> > + <xsl:text> > +</xsl:text> > + </xsl:for-each> > + <hr/> > + > + <h3>Archives:</h3> > + > + <xsl:for-each > select="descendant::resource[type/@name="archive"]"> > + + <xsl:value-of select="@name"/> > + <br/> > + </xsl:for-each> > + <hr/> > + > + <p> > + Files with Apache License headers will be marked AL<br/> > + Binary files (which do not require AL headers) will be marked > B<br/> > + Compressed archives will be marked A<br/> > + Notices, licenses etc will be marked N<br/> > + </p> > + > + <xsl:for-each select="descendant::resource"> > + <xsl:choose> > + <xsl:when > test="license-approval/@name="false"">!</xsl:when> > + <xsl:otherwise><xsl:text> </xsl:text></xsl:otherwise> > + </xsl:choose> > + <xsl:choose> > + <xsl:when test="type/@name="notice"">N > </xsl:when> > + <xsl:when test="type/@name="archive"">A > </xsl:when> > + <xsl:when test="type/@name="binary"">B > </xsl:when> > + <xsl:when > test="type/@name="standard""><xsl:value-of > select="header-type/@name"/></xsl:when> > + <xsl:otherwise>!!!!!</xsl:otherwise> > + </xsl:choose> > + <xsl:text> </xsl:text> > + <xsl:value-of select="@name"/><br/> > + <xsl:text> > + </xsl:text> > + </xsl:for-each> > + <hr/> > + > + <h3>Printing headers for files without AL header...</h3> > + > + <xsl:for-each > select="descendant::resource[header-type/@name="?????"]"> > + > + <h4><xsl:value-of select="@name"/></h4> > + <xsl:value-of select="header-sample"/> > + <hr/> > + </xsl:for-each> > + <br/> > + > + <!-- <xsl:apply-templates select="resource"/> > + <xsl:apply-templates select="header-sample"/> > + <xsl:apply-templates select="header-type"/> > + <xsl:apply-templates select="license-family"/> > + <xsl:apply-templates select="license-approval"/> > + <xsl:apply-templates select="type"/> --> > + > + </xsl:template> > + > + <xsl:template match="resource"> > + <div> > + <h3>Resource: <xsl:value-of select="@name"/></h3> > + <xsl:apply-templates/> > + </div> > + </xsl:template> > + > + <xsl:template match="header-sample"> > + <xsl:if test="normalize-space(.) != ''"> > + <h4>First few lines of non-compliant file</h4> > + <p> > + <xsl:value-of select="."/> > + </p> > + </xsl:if> > + <h4>Other Info:</h4> > + </xsl:template> > + > + <xsl:template match="header-type"> > + Header Type: <xsl:value-of select="@name"/> > + <br/> > + </xsl:template> > + > + <xsl:template match="license-family"> > + License Family: <xsl:value-of select="@name"/> > + <br/> > + </xsl:template> > + > + <xsl:template match="license-approval"> > + License Approval: <xsl:value-of select="@name"/> > + <br/> > + </xsl:template> > + > + <xsl:template match="type"> > + Type: <xsl:value-of select="@name"/> > + <br/> > + </xsl:template> > + > + <xsl:template name="generated"> > + </xsl:template> > +</xsl:transform> > \ No newline at end of file > > > --------------------------------------------------------------------- > To unsubscribe, e-mail: [email protected] > For additional commands, e-mail: [email protected] >
