org.opensearch.gradle.precommit.LicenseHeadersTask.groovy Maven / Gradle / Ivy
Show all versions of build-tools Show documentation
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
*
* Modifications Copyright OpenSearch Contributors. See
* GitHub history for details.
*/
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch 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.
*/
package org.opensearch.gradle.precommit
import org.apache.rat.anttasks.Report
import org.apache.rat.anttasks.SubstringLicenseMatcher
import org.apache.rat.license.SimpleLicenseFamily
import org.opensearch.gradle.AntTask
import org.gradle.api.file.FileCollection
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.IgnoreEmptyDirectories;
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.PathSensitive
import org.gradle.api.tasks.PathSensitivity
import org.gradle.api.tasks.SkipWhenEmpty
import java.nio.file.Files
/**
* Checks files for license headers.
*
* This is a port of the apache lucene check
*/
class LicenseHeadersTask extends AntTask {
@OutputFile
File reportFile = new File(project.buildDir, 'reports/licenseHeaders/rat.log')
/** Allowed license families for this project. */
@Input
List approvedLicenses = ['Apache', 'Generated', 'SPDX', 'Vendored']
/**
* Files that should be excluded from the license header check. Use with extreme care, only in situations where the license on the
* source file is compatible with the codebase but we do not want to add the license to the list of approved headers (to avoid the
* possibility of inadvertently using the license on our own source files).
*/
@Input
List excludes = []
/**
* Additional license families that may be found. The key is the license category name (5 characters),
* followed by the family name and the value list of patterns to search for.
*/
protected Map additionalLicenses = new HashMap<>()
LicenseHeadersTask() {
description = "Checks sources for missing, incorrect, or unacceptable license headers"
}
/**
* The list of java files to check. protected so the afterEvaluate closure in the
* constructor can write to it.
*/
@InputFiles
@SkipWhenEmpty
@IgnoreEmptyDirectories
@PathSensitive(PathSensitivity.RELATIVE)
List getJavaFiles() {
return project.sourceSets.collect({it.allJava})
}
/**
* Add a new license type.
*
* The license may be added to the {@link #approvedLicenses} using the {@code familyName}.
*
* @param categoryName A 5-character string identifier for the license
* @param familyName An expanded string name for the license
* @param pattern A pattern to search for, which if found, indicates a file contains the license
*/
void additionalLicense(String categoryName, String familyName, String pattern) {
if (categoryName.length() != 5) {
throw new IllegalArgumentException("License category name must be exactly 5 characters, got ${categoryName}");
}
additionalLicenses.put(categoryName + familyName, pattern);
}
@Override
protected void runAnt(AntBuilder ant) {
ant.project.addTaskDefinition('ratReport', Report)
ant.project.addDataTypeDefinition('substringMatcher', SubstringLicenseMatcher)
ant.project.addDataTypeDefinition('approvedLicense', SimpleLicenseFamily)
Files.deleteIfExists(reportFile.toPath())
// run rat, going to the file
ant.ratReport(reportFile: reportFile.absolutePath, addDefaultLicenseMatchers: true) {
for (FileCollection dirSet : javaFiles) {
for (File dir: dirSet.srcDirs) {
// sometimes these dirs don't exist, e.g. site-plugin has no actual java src/main...
if (dir.exists()) {
ant.fileset(dir: dir, excludes: excludes.join(' '))
}
}
}
// BSD 4-clause stuff (is disallowed below)
// we keep this here, in case someone adds BSD code for some reason, it should never be allowed.
substringMatcher(licenseFamilyCategory: "BSD4 ",
licenseFamilyName: "Original BSD License (with advertising clause)") {
pattern(substring: "All advertising materials")
}
// Apache
substringMatcher(licenseFamilyCategory: "AL ",
licenseFamilyName: "Apache") {
// Apache license (ES)
pattern(substring: "Licensed to Elasticsearch under one or more contributor")
}
// SPDX
substringMatcher(licenseFamilyCategory: "SPDX ",
licenseFamilyName: "SPDX") {
// Apache license (OpenSearch)
pattern(substring: "SPDX-License-Identifier: Apache-2.0")
pattern(substring: "Copyright OpenSearch Contributors.")
}
// Generated resources
substringMatcher(licenseFamilyCategory: "GEN ",
licenseFamilyName: "Generated") {
// parsers generated by antlr
pattern(substring: "ANTLR GENERATED CODE")
}
// Vendored Code
substringMatcher(licenseFamilyCategory: "VEN ",
licenseFamilyName: "Vendored") {
pattern(substring: "@notice")
}
// license types added by the project
for (Map.Entry additional : additionalLicenses.entrySet()) {
String category = additional.getKey().substring(0, 5)
String family = additional.getKey().substring(5)
substringMatcher(licenseFamilyCategory: category,
licenseFamilyName: family) {
pattern(substring: additional.getValue())
}
}
// approved categories
for (String licenseFamily : approvedLicenses) {
approvedLicense(familyName: licenseFamily)
}
}
// check the license file for any errors, this should be fast.
boolean zeroUnknownLicenses = false
boolean foundProblemsWithFiles = false
reportFile.eachLine('UTF-8') { line ->
if (line.startsWith("0 Unknown Licenses")) {
zeroUnknownLicenses = true
}
if (line.startsWith(" !")) {
foundProblemsWithFiles = true
}
}
if (zeroUnknownLicenses == false || foundProblemsWithFiles) {
// print the unapproved license section, usually its all you need to fix problems.
int sectionNumber = 0
reportFile.eachLine('UTF-8') { line ->
if (line.startsWith("*******************************")) {
sectionNumber++
} else {
if (sectionNumber == 2) {
logger.error(line)
}
}
}
throw new IllegalStateException("License header problems were found! Full details: " + reportFile.absolutePath)
}
}
}