This is an automated email from the ASF dual-hosted git repository. chesnay pushed a commit to branch release-1.12 in repository https://gitbox.apache.org/repos/asf/flink.git
commit 1f184e6b4fd184280eadaddac366f5ae67d0c8c7 Author: Chesnay Schepler <[email protected]> AuthorDate: Mon Dec 7 03:03:43 2020 +0100 [FLINK-20455][build][legal] Add jar license checker --- tools/ci/compile.sh | 10 +- tools/ci/java-ci-tools/pom.xml | 10 + .../tools/ci/licensecheck/JarFileChecker.java | 156 ++++++++ .../tools/ci/licensecheck/LicenseChecker.java | 7 +- .../tools/ci/licensecheck/JarFileCheckerTest.java | 444 +++++++++++++++++++++ tools/ci/license_check.sh | 3 +- 6 files changed, 625 insertions(+), 5 deletions(-) diff --git a/tools/ci/compile.sh b/tools/ci/compile.sh index d91d24a..14e03fe 100755 --- a/tools/ci/compile.sh +++ b/tools/ci/compile.sh @@ -29,6 +29,10 @@ fi CI_DIR="$HERE/../ci" MVN_CLEAN_COMPILE_OUT="/tmp/clean_compile.out" +# Deploy into this directory, to run license checks on all jars staged for deployment. +# This helps us ensure that ALL artifacts we deploy to maven central adhere to our license conditions. +MVN_VALIDATION_DIR="/tmp/flink-validation-deployment" + # source required ci scripts source "${CI_DIR}/stage.sh" source "${CI_DIR}/shade.sh" @@ -43,7 +47,7 @@ echo "========================================================================== EXIT_CODE=0 -run_mvn clean install $MAVEN_OPTS -Dflink.convergence.phase=install -Pcheck-convergence -Dflink.forkCount=2 \ +run_mvn clean deploy -DaltDeploymentRepository=validation_repository::default::file:$MVN_VALIDATION_DIR $MAVEN_OPTS -Dflink.convergence.phase=install -Pcheck-convergence -Dflink.forkCount=2 \ -Dflink.forkCountTestPackage=2 -Dmaven.javadoc.skip=true -U -DskipTests | tee $MVN_CLEAN_COMPILE_OUT EXIT_CODE=${PIPESTATUS[0]} @@ -107,8 +111,10 @@ EXIT_CODE=$(($EXIT_CODE+$?)) echo "============ Run license check ============" +find $MVN_VALIDATION_DIR + if [[ ${PROFILE} != *"scala-2.12"* ]]; then - ${CI_DIR}/license_check.sh $MVN_CLEAN_COMPILE_OUT $CI_DIR $(pwd) || exit $? + ${CI_DIR}/license_check.sh $MVN_CLEAN_COMPILE_OUT $CI_DIR $(pwd) $MVN_VALIDATION_DIR || exit $? fi exit $EXIT_CODE diff --git a/tools/ci/java-ci-tools/pom.xml b/tools/ci/java-ci-tools/pom.xml index fdfb268..bd75a46 100644 --- a/tools/ci/java-ci-tools/pom.xml +++ b/tools/ci/java-ci-tools/pom.xml @@ -35,6 +35,16 @@ under the License. <dependencies> <dependency> + <groupId>org.apache.flink</groupId> + <artifactId>flink-annotations</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.apache.flink</groupId> + <artifactId>flink-test-utils-junit</artifactId> + <scope>test</scope> + </dependency> + <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>30.0-jre</version> diff --git a/tools/ci/java-ci-tools/src/main/java/org/apache/flink/tools/ci/licensecheck/JarFileChecker.java b/tools/ci/java-ci-tools/src/main/java/org/apache/flink/tools/ci/licensecheck/JarFileChecker.java new file mode 100644 index 0000000..dbd1945 --- /dev/null +++ b/tools/ci/java-ci-tools/src/main/java/org/apache/flink/tools/ci/licensecheck/JarFileChecker.java @@ -0,0 +1,156 @@ +/* + * 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. + */ + +package org.apache.flink.tools.ci.licensecheck; + +import org.apache.flink.annotation.VisibleForTesting; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Checks the Jar files created by the build process. + */ +public class JarFileChecker { + private static final Logger LOG = LoggerFactory.getLogger(JarFileChecker.class); + + public static int checkPath(Path path) throws Exception { + List<Path> files = getBuildJars(path); + LOG.info("Checking directory {} with a total of {} jar files.", path, files.size()); + + int severeIssues = 0; + for (Path file : files) { + severeIssues += checkJar(file); + } + + return severeIssues; + } + + private static List<Path> getBuildJars(Path path) throws IOException { + return Files.walk(path) + .filter(file -> file.toString().endsWith(".jar")) + .collect(Collectors.toList()); + } + + @VisibleForTesting + static int checkJar(Path file) throws Exception { + final URI uri = file.toUri(); + + int numSevereIssues = 0; + try (final FileSystem fileSystem = FileSystems.newFileSystem(new URI("jar:file", uri.getHost(), uri.getPath(), uri.getFragment()), Collections.emptyMap())) { + if (isTestJarAndEmpty(file, fileSystem.getPath("/"))) { + return 0; + } + if (!noticeFileExistsAndIsValid(fileSystem.getPath("META-INF", "NOTICE"), file)) { + numSevereIssues++; + } + if (!licenseFileExistsAndIsValid(fileSystem.getPath("META-INF", "LICENSE"), file)) { + numSevereIssues++; + } + + numSevereIssues += getNumLicenseFilesOutsideMetaInfDirectory(file, fileSystem.getPath("/")); + } + return numSevereIssues; + } + + private static boolean isTestJarAndEmpty(Path jar, Path jarRoot) throws IOException { + if (jar.getFileName().toString().endsWith("-tests.jar")) { + try (Stream<Path> files = Files.walk(jarRoot)) { + long numClassFiles = files + .filter(path -> !path.equals(jarRoot)) + .filter(path -> path.getFileName().toString().endsWith(".class")) + .count(); + if (numClassFiles == 0) { + return true; + } + } + } + + return false; + } + + private static boolean noticeFileExistsAndIsValid(Path noticeFile, Path jar) throws IOException { + if (!Files.exists(noticeFile)) { + LOG.error("Missing META-INF/NOTICE in {}", jar); + return false; + } + + final String noticeFileContents = new String(Files.readAllBytes(noticeFile), StandardCharsets.UTF_8); + if (!noticeFileContents.toLowerCase().contains("flink") || !noticeFileContents.contains("The Apache Software Foundation")) { + LOG.error("The notice file in {} does not contain the expected entries.", jar); + return false; + } + + return true; + } + + private static boolean licenseFileExistsAndIsValid(Path licenseFile, Path jar) throws IOException { + if (!Files.exists(licenseFile)) { + LOG.error("Missing META-INF/LICENSE in {}", jar); + return false; + } + + final String licenseFileContents = new String(Files.readAllBytes(licenseFile), StandardCharsets.UTF_8); + if (!licenseFileContents.contains("Apache License") || !licenseFileContents.contains("Version 2.0, January 2004")) { + LOG.error("The license file in {} does not contain the expected entries.", jar); + return false; + } + + return true; + } + + private static int getNumLicenseFilesOutsideMetaInfDirectory(Path jar, Path jarRoot) throws IOException { + try (Stream<Path> files = Files.walk(jarRoot)) { + /* + * LICENSE or NOTICE files found outside of the META-INF directory are most likely shading mistakes (we are including the files from other dependencies, thus providing an invalid LICENSE file) + * + * <p>In such a case, we recommend updating the shading exclusions, and adding the license file to META-INF/licenses. + */ + final List<String> filesWithIssues = files + .filter(path -> !path.equals(jarRoot)) + .filter(path -> getFileName(path).contains("license") || getFileName(path).contains("notice")) + .filter(path -> !Files.isDirectory(path)) // ignore directories, e.g. "license/" + .filter(path -> !getFileName(path).endsWith(".class")) // some class files contain LICENSE in their name + .filter(path -> !getFileName(path).endsWith(".ftl")) // a false positive in flink-python + .map(Path::toString) + .filter(path -> !path.contains("META-INF")) // license files in META-INF are expected + .filter(path -> !path.endsWith("web/3rdpartylicenses.txt")) // a false positive in flink-runtime-web + .collect(Collectors.toList()); + for (String fileWithIssue : filesWithIssues) { + LOG.error("Jar file {} contains a LICENSE file in an unexpected location: {}", jar, fileWithIssue); + } + return filesWithIssues.size(); + } + } + + private static String getFileName(Path path) { + return path.getFileName().toString().toLowerCase(); + } +} diff --git a/tools/ci/java-ci-tools/src/main/java/org/apache/flink/tools/ci/licensecheck/LicenseChecker.java b/tools/ci/java-ci-tools/src/main/java/org/apache/flink/tools/ci/licensecheck/LicenseChecker.java index 240e062..1f066e5 100644 --- a/tools/ci/java-ci-tools/src/main/java/org/apache/flink/tools/ci/licensecheck/LicenseChecker.java +++ b/tools/ci/java-ci-tools/src/main/java/org/apache/flink/tools/ci/licensecheck/LicenseChecker.java @@ -32,9 +32,9 @@ public class LicenseChecker { private static final Logger LOG = LoggerFactory.getLogger(LicenseChecker.class); - public static void main(String[] args) throws IOException { + public static void main(String[] args) throws Exception { if (args.length < 2) { - System.out.println("Usage: LicenseChecker <pathMavenBuildOutput> <pathFlinkRoot>"); + System.out.println("Usage: LicenseChecker <pathMavenBuildOutput> <pathFlinkRoot> <pathFlinkDeployed>"); System.exit(1); } LOG.warn("THIS UTILITY IS ONLY CHECKING FOR COMMON LICENSING MISTAKES. A MANUAL CHECK OF THE NOTICE FILES, DEPLOYED ARTIFACTS, ETC. IS STILL NEEDED!"); @@ -42,6 +42,9 @@ public class LicenseChecker { NoticeFileChecker noticeChecker = new NoticeFileChecker(); int severeIssueCount = noticeChecker.run(new File(args[0]), Paths.get(args[1])); + JarFileChecker jarChecker = new JarFileChecker(); + severeIssueCount += jarChecker.checkPath(Paths.get(args[2])); + if (severeIssueCount > 0) { LOG.warn("Found a total of {} severe license issues", severeIssueCount); diff --git a/tools/ci/java-ci-tools/src/test/java/org/apache/flink/tools/ci/licensecheck/JarFileCheckerTest.java b/tools/ci/java-ci-tools/src/test/java/org/apache/flink/tools/ci/licensecheck/JarFileCheckerTest.java new file mode 100644 index 0000000..f9fb664 --- /dev/null +++ b/tools/ci/java-ci-tools/src/test/java/org/apache/flink/tools/ci/licensecheck/JarFileCheckerTest.java @@ -0,0 +1,444 @@ +/* + * 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. + */ + +package org.apache.flink.tools.ci.licensecheck; + +import org.apache.flink.util.TestLogger; + +import org.junit.ClassRule; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +import java.net.URI; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +/** + * Tests for the {@link JarFileChecker}. + * + * <p>For dev purposes, generate a deploy-directory with: + * mvn clean deploy -DaltDeploymentRepository=snapshot-repo::default::file:/tmp/flink-deployment -DskipTests -Drat.skip + * and add a test checking that directory. + */ +public class JarFileCheckerTest extends TestLogger { + + @ClassRule + public static final TemporaryFolder TMP = new TemporaryFolder(); + + private static final List<String> VALID_NOTICE_PATH = Arrays.asList("META-INF", "NOTICE"); + private static final List<String> VALID_LICENSE_PATH = Arrays.asList("META-INF", "LICENSE"); + + @Test + public void testValidJarAccepted() throws Exception { + assertThat(JarFileChecker.checkJar( + createJar( + Entry.fileEntry(VALID_NOTICE_CONTENTS, VALID_NOTICE_PATH), + Entry.fileEntry(VALID_LICENSE_CONTENTS, VALID_LICENSE_PATH))), + is(0)); + } + + @Test + public void testRejectedOnMissingNoticeFile() throws Exception { + assertThat(JarFileChecker.checkJar( + createJar( + Entry.fileEntry(VALID_LICENSE_CONTENTS, VALID_LICENSE_PATH))), + is(1)); + } + + @Test + public void testRejectedOnInvalidNoticeFile() throws Exception { + assertThat(JarFileChecker.checkJar( + createJar( + Entry.fileEntry(INVALID_NOTICE_CONTENTS, VALID_NOTICE_PATH), + Entry.fileEntry(VALID_LICENSE_CONTENTS, VALID_LICENSE_PATH))), + is(1)); + } + + @Test + public void testRejectedOnNoticeFileInRoot() throws Exception { + assertThat(JarFileChecker.checkJar( + createJar( + Entry.fileEntry(VALID_NOTICE_CONTENTS, VALID_NOTICE_PATH), + Entry.fileEntry(VALID_LICENSE_CONTENTS, VALID_LICENSE_PATH), + Entry.fileEntry(VALID_NOTICE_CONTENTS, Arrays.asList("some_custom_notice")))), + is(1)); + } + + @Test + public void testRejectedOnMissingLicenseFile() throws Exception { + assertThat(JarFileChecker.checkJar( + createJar( + Entry.fileEntry(VALID_NOTICE_CONTENTS, VALID_NOTICE_PATH))), + is(1)); + } + + @Test + public void testRejectedOnInvalidLicenseFile() throws Exception { + assertThat(JarFileChecker.checkJar( + createJar( + Entry.fileEntry(VALID_NOTICE_CONTENTS, VALID_NOTICE_PATH), + Entry.fileEntry(INVALID_LICENSE_CONTENTS, VALID_LICENSE_PATH))), + is(1)); + } + + @Test + public void testRejectedOnLicenseFileInRoot() throws Exception { + assertThat(JarFileChecker.checkJar( + createJar( + Entry.fileEntry(VALID_NOTICE_CONTENTS, VALID_NOTICE_PATH), + Entry.fileEntry(VALID_LICENSE_CONTENTS, VALID_LICENSE_PATH), + Entry.fileEntry(VALID_LICENSE_CONTENTS, Arrays.asList("some_custom_license")))), + is(1)); + } + + @Test + public void testRejectedOnLicenseFileInSomeDirectory() throws Exception { + assertThat(JarFileChecker.checkJar( + createJar( + Entry.fileEntry(VALID_NOTICE_CONTENTS, VALID_NOTICE_PATH), + Entry.fileEntry(VALID_LICENSE_CONTENTS, VALID_LICENSE_PATH), + Entry.fileEntry(VALID_LICENSE_CONTENTS, Arrays.asList("some", "directory", "some_custom_license")))), + is(1)); + } + + @Ignore("Currently not checked, but we may want to enforce this in the future to reduce ambiguity.") + public void testRejectedOnAdditionalLicenseFileInMetaInf() throws Exception { + assertThat(JarFileChecker.checkJar( + createJar( + Entry.fileEntry(VALID_NOTICE_CONTENTS, VALID_NOTICE_PATH), + Entry.fileEntry(VALID_LICENSE_CONTENTS, VALID_LICENSE_PATH), + Entry.fileEntry(VALID_LICENSE_CONTENTS, Arrays.asList("META-INF", "LICENSE.txt")))), + is(1)); + } + + @Test + public void testIgnoreLicenseDirectories() throws Exception { + assertThat(JarFileChecker.checkJar( + createJar( + Entry.fileEntry(VALID_NOTICE_CONTENTS, VALID_NOTICE_PATH), + Entry.fileEntry(VALID_LICENSE_CONTENTS, VALID_LICENSE_PATH), + Entry.directoryEntry(Arrays.asList("some", "license", "directory")))), + is(0)); + } + + @Test + public void testIgnoreClassFiles() throws Exception { + assertThat(JarFileChecker.checkJar( + createJar( + Entry.fileEntry(VALID_NOTICE_CONTENTS, VALID_NOTICE_PATH), + Entry.fileEntry(VALID_LICENSE_CONTENTS, VALID_LICENSE_PATH), + Entry.fileEntry("content", Arrays.asList("SomeLicenseClass.class")))), + is(0)); + } + + @Test + public void testIgnoreFtlFiles() throws Exception { + assertThat(JarFileChecker.checkJar( + createJar( + Entry.fileEntry(VALID_NOTICE_CONTENTS, VALID_NOTICE_PATH), + Entry.fileEntry(VALID_LICENSE_CONTENTS, VALID_LICENSE_PATH), + Entry.fileEntry("content", Arrays.asList("SomeLicenseFile.ftl")))), + is(0)); + } + + @Test + public void testIgnoreWebThirdPartyLicenses() throws Exception { + assertThat(JarFileChecker.checkJar( + createJar( + Entry.fileEntry(VALID_NOTICE_CONTENTS, VALID_NOTICE_PATH), + Entry.fileEntry(VALID_LICENSE_CONTENTS, VALID_LICENSE_PATH), + Entry.fileEntry("class contents", Arrays.asList("web", "3rdpartylicenses.txt")))), + is(0)); + } + + private static class Entry { + final String contents; + final List<String> path; + final boolean isDirectory; + + public static Entry directoryEntry(List<String> path) { + return new Entry("", path, true); + } + + public static Entry fileEntry(String contents, List<String> path) { + return new Entry(contents, path, false); + } + + private Entry(String contents, List<String> path, boolean isDirectory) { + this.contents = contents; + this.path = path; + this.isDirectory = isDirectory; + } + } + + private static Path createJar(Entry... entries) throws Exception { + final Path path = TMP.getRoot().toPath().resolve(UUID.randomUUID().toString() + ".jar"); + + final URI uriWithoutScheme = path.toUri(); + + final URI uri = new URI("jar:file", uriWithoutScheme.getHost(), uriWithoutScheme.getPath(), uriWithoutScheme.getFragment()); + + // causes FileSystems#newFileSystem to automatically create a valid zip file + // this is easier than manually creating a valid empty zip file manually + final Map<String, String> env = new HashMap<>(); + env.put("create", "true"); + + try (FileSystem zip = FileSystems.newFileSystem(uri, env)) { + // shortcut to getting the single root + final Path root = zip.getPath("").toAbsolutePath(); + for (Entry entry : entries) { + final Path zipPath = root.resolve(zip.getPath(entry.path.get(0), entry.path.subList(1, entry.path.size()).toArray(new String[]{}))); + if (entry.isDirectory) { + Files.createDirectories(zipPath); + } else { + Files.createDirectories(zipPath.getParent()); + Files.write(zipPath, entry.contents.getBytes()); + } + } + } + return path; + } + + private static final String INVALID_NOTICE_CONTENTS = "" + + "invalid"; + + private static final String VALID_NOTICE_CONTENTS = "" + + "Flink : SomeModule\n" + + "Copyright 2014-2020 The Apache Software Foundation\n" + + "\n" + + "This product includes software developed at\n" + + "The Apache Software Foundation (http://www.apache.org/)."; + + private static final String INVALID_LICENSE_CONTENTS = "" + + "invalid"; + + private static final String VALID_LICENSE_CONTENTS = "" + + "\n" + + " Apache License\n" + + " Version 2.0, January 2004\n" + + " http://www.apache.org/licenses/\n" + + "\n" + + " TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n" + + "\n" + + " 1. Definitions.\n" + + "\n" + + " \"License\" shall mean the terms and conditions for use, reproduction,\n" + + " and distribution as defined by Sections 1 through 9 of this document.\n" + + "\n" + + " \"Licensor\" shall mean the copyright owner or entity authorized by\n" + + " the copyright owner that is granting the License.\n" + + "\n" + + " \"Legal Entity\" shall mean the union of the acting entity and all\n" + + " other entities that control, are controlled by, or are under common\n" + + " control with that entity. For the purposes of this definition,\n" + + " \"control\" means (i) the power, direct or indirect, to cause the\n" + + " direction or management of such entity, whether by contract or\n" + + " otherwise, or (ii) ownership of fifty percent (50%) or more of the\n" + + " outstanding shares, or (iii) beneficial ownership of such entity.\n" + + "\n" + + " \"You\" (or \"Your\") shall mean an individual or Legal Entity\n" + + " exercising permissions granted by this License.\n" + + "\n" + + " \"Source\" form shall mean the preferred form for making modifications,\n" + + " including but not limited to software source code, documentation\n" + + " source, and configuration files.\n" + + "\n" + + " \"Object\" form shall mean any form resulting from mechanical\n" + + " transformation or translation of a Source form, including but\n" + + " not limited to compiled object code, generated documentation,\n" + + " and conversions to other media types.\n" + + "\n" + + " \"Work\" shall mean the work of authorship, whether in Source or\n" + + " Object form, made available under the License, as indicated by a\n" + + " copyright notice that is included in or attached to the work\n" + + " (an example is provided in the Appendix below).\n" + + "\n" + + " \"Derivative Works\" shall mean any work, whether in Source or Object\n" + + " form, that is based on (or derived from) the Work and for which the\n" + + " editorial revisions, annotations, elaborations, or other modifications\n" + + " represent, as a whole, an original work of authorship. For the purposes\n" + + " of this License, Derivative Works shall not include works that remain\n" + + " separable from, or merely link (or bind by name) to the interfaces of,\n" + + " the Work and Derivative Works thereof.\n" + + "\n" + + " \"Contribution\" shall mean any work of authorship, including\n" + + " the original version of the Work and any modifications or additions\n" + + " to that Work or Derivative Works thereof, that is intentionally\n" + + " submitted to Licensor for inclusion in the Work by the copyright owner\n" + + " or by an individual or Legal Entity authorized to submit on behalf of\n" + + " the copyright owner. For the purposes of this definition, \"submitted\"\n" + + " means any form of electronic, verbal, or written communication sent\n" + + " to the Licensor or its representatives, including but not limited to\n" + + " communication on electronic mailing lists, source code control systems,\n" + + " and issue tracking systems that are managed by, or on behalf of, the\n" + + " Licensor for the purpose of discussing and improving the Work, but\n" + + " excluding communication that is conspicuously marked or otherwise\n" + + " designated in writing by the copyright owner as \"Not a Contribution.\"\n" + + "\n" + + " \"Contributor\" shall mean Licensor and any individual or Legal Entity\n" + + " on behalf of whom a Contribution has been received by Licensor and\n" + + " subsequently incorporated within the Work.\n" + + "\n" + + " 2. Grant of Copyright License. Subject to the terms and conditions of\n" + + " this License, each Contributor hereby grants to You a perpetual,\n" + + " worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n" + + " copyright license to reproduce, prepare Derivative Works of,\n" + + " publicly display, publicly perform, sublicense, and distribute the\n" + + " Work and such Derivative Works in Source or Object form.\n" + + "\n" + + " 3. Grant of Patent License. Subject to the terms and conditions of\n" + + " this License, each Contributor hereby grants to You a perpetual,\n" + + " worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n" + + " (except as stated in this section) patent license to make, have made,\n" + + " use, offer to sell, sell, import, and otherwise transfer the Work,\n" + + " where such license applies only to those patent claims licensable\n" + + " by such Contributor that are necessarily infringed by their\n" + + " Contribution(s) alone or by combination of their Contribution(s)\n" + + " with the Work to which such Contribution(s) was submitted. If You\n" + + " institute patent litigation against any entity (including a\n" + + " cross-claim or counterclaim in a lawsuit) alleging that the Work\n" + + " or a Contribution incorporated within the Work constitutes direct\n" + + " or contributory patent infringement, then any patent licenses\n" + + " granted to You under this License for that Work shall terminate\n" + + " as of the date such litigation is filed.\n" + + "\n" + + " 4. Redistribution. You may reproduce and distribute copies of the\n" + + " Work or Derivative Works thereof in any medium, with or without\n" + + " modifications, and in Source or Object form, provided that You\n" + + " meet the following conditions:\n" + + "\n" + + " (a) You must give any other recipients of the Work or\n" + + " Derivative Works a copy of this License; and\n" + + "\n" + + " (b) You must cause any modified files to carry prominent notices\n" + + " stating that You changed the files; and\n" + + "\n" + + " (c) You must retain, in the Source form of any Derivative Works\n" + + " that You distribute, all copyright, patent, trademark, and\n" + + " attribution notices from the Source form of the Work,\n" + + " excluding those notices that do not pertain to any part of\n" + + " the Derivative Works; and\n" + + "\n" + + " (d) If the Work includes a \"NOTICE\" text file as part of its\n" + + " distribution, then any Derivative Works that You distribute must\n" + + " include a readable copy of the attribution notices contained\n" + + " within such NOTICE file, excluding those notices that do not\n" + + " pertain to any part of the Derivative Works, in at least one\n" + + " of the following places: within a NOTICE text file distributed\n" + + " as part of the Derivative Works; within the Source form or\n" + + " documentation, if provided along with the Derivative Works; or,\n" + + " within a display generated by the Derivative Works, if and\n" + + " wherever such third-party notices normally appear. The contents\n" + + " of the NOTICE file are for informational purposes only and\n" + + " do not modify the License. You may add Your own attribution\n" + + " notices within Derivative Works that You distribute, alongside\n" + + " or as an addendum to the NOTICE text from the Work, provided\n" + + " that such additional attribution notices cannot be construed\n" + + " as modifying the License.\n" + + "\n" + + " You may add Your own copyright statement to Your modifications and\n" + + " may provide additional or different license terms and conditions\n" + + " for use, reproduction, or distribution of Your modifications, or\n" + + " for any such Derivative Works as a whole, provided Your use,\n" + + " reproduction, and distribution of the Work otherwise complies with\n" + + " the conditions stated in this License.\n" + + "\n" + + " 5. Submission of Contributions. Unless You explicitly state otherwise,\n" + + " any Contribution intentionally submitted for inclusion in the Work\n" + + " by You to the Licensor shall be under the terms and conditions of\n" + + " this License, without any additional terms or conditions.\n" + + " Notwithstanding the above, nothing herein shall supersede or modify\n" + + " the terms of any separate license agreement you may have executed\n" + + " with Licensor regarding such Contributions.\n" + + "\n" + + " 6. Trademarks. This License does not grant permission to use the trade\n" + + " names, trademarks, service marks, or product names of the Licensor,\n" + + " except as required for reasonable and customary use in describing the\n" + + " origin of the Work and reproducing the content of the NOTICE file.\n" + + "\n" + + " 7. Disclaimer of Warranty. Unless required by applicable law or\n" + + " agreed to in writing, Licensor provides the Work (and each\n" + + " Contributor provides its Contributions) on an \"AS IS\" BASIS,\n" + + " WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n" + + " implied, including, without limitation, any warranties or conditions\n" + + " of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n" + + " PARTICULAR PURPOSE. You are solely responsible for determining the\n" + + " appropriateness of using or redistributing the Work and assume any\n" + + " risks associated with Your exercise of permissions under this License.\n" + + "\n" + + " 8. Limitation of Liability. In no event and under no legal theory,\n" + + " whether in tort (including negligence), contract, or otherwise,\n" + + " unless required by applicable law (such as deliberate and grossly\n" + + " negligent acts) or agreed to in writing, shall any Contributor be\n" + + " liable to You for damages, including any direct, indirect, special,\n" + + " incidental, or consequential damages of any character arising as a\n" + + " result of this License or out of the use or inability to use the\n" + + " Work (including but not limited to damages for loss of goodwill,\n" + + " work stoppage, computer failure or malfunction, or any and all\n" + + " other commercial damages or losses), even if such Contributor\n" + + " has been advised of the possibility of such damages.\n" + + "\n" + + " 9. Accepting Warranty or Additional Liability. While redistributing\n" + + " the Work or Derivative Works thereof, You may choose to offer,\n" + + " and charge a fee for, acceptance of support, warranty, indemnity,\n" + + " or other liability obligations and/or rights consistent with this\n" + + " License. However, in accepting such obligations, You may act only\n" + + " on Your own behalf and on Your sole responsibility, not on behalf\n" + + " of any other Contributor, and only if You agree to indemnify,\n" + + " defend, and hold each Contributor harmless for any liability\n" + + " incurred by, or claims asserted against, such Contributor by reason\n" + + " of your accepting any such warranty or additional liability.\n" + + "\n" + + " END OF TERMS AND CONDITIONS\n" + + "\n" + + " APPENDIX: How to apply the Apache License to your work.\n" + + "\n" + + " To apply the Apache License to your work, attach the following\n" + + " boilerplate notice, with the fields enclosed by brackets \"[]\"\n" + + " replaced with your own identifying information. (Don't include\n" + + " the brackets!) The text should be enclosed in the appropriate\n" + + " comment syntax for the file format. We also recommend that a\n" + + " file or class name and description of purpose be included on the\n" + + " same \"printed page\" as the copyright notice for easier\n" + + " identification within third-party archives.\n" + + "\n" + + " Copyright [yyyy] [name of copyright owner]\n" + + "\n" + + " Licensed under the Apache License, Version 2.0 (the \"License\");\n" + + " you may not use this file except in compliance with the License.\n" + + " You may obtain a copy of the License at\n" + + "\n" + + " http://www.apache.org/licenses/LICENSE-2.0\n" + + "\n" + + " Unless required by applicable law or agreed to in writing, software\n" + + " distributed under the License is distributed on an \"AS IS\" BASIS,\n" + + " WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" + + " See the License for the specific language governing permissions and\n" + + " limitations under the License.\n"; + +} diff --git a/tools/ci/license_check.sh b/tools/ci/license_check.sh index 5a8b87f..34f0916 100755 --- a/tools/ci/license_check.sh +++ b/tools/ci/license_check.sh @@ -20,12 +20,13 @@ MVN_CLEAN_COMPILE_OUT=$1 CI_DIR=$2 FLINK_ROOT=$3 +FLINK_DEPLOYED_ROOT=$4 source "${CI_DIR}/maven-utils.sh" cd $CI_DIR/java-ci-tools/ -run_mvn exec:java -Dexec.mainClass=org.apache.flink.tools.ci.licensecheck.LicenseChecker -Dexec.args=\"$MVN_CLEAN_COMPILE_OUT $FLINK_ROOT\" +run_mvn exec:java -Dexec.mainClass=org.apache.flink.tools.ci.licensecheck.LicenseChecker -Dexec.args=\"$MVN_CLEAN_COMPILE_OUT $FLINK_ROOT $FLINK_DEPLOYED_ROOT\" EXIT_CODE=$? if [ $EXIT_CODE != 0 ]; then
