diff --git a/.circleci/config.yml b/.circleci/config.yml index e3cadb0b6788..f7051b683e40 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -26,7 +26,7 @@ jobs: - restore-cache: *restore-cache - run: yarn --no-progress - save-cache: *save-cache - - run: yarn lint --format junit -o reports/junit/js-lint-results.xml && yarn typecheck && yarn lint-es5-build --format junit -o reports/junit/js-es5-lint-results.xml && yarn lint:md:ci + - run: yarn lint --format junit -o reports/junit/js-lint-results.xml && yarn typecheck && yarn lint-es5-build --format junit -o reports/junit/js-es5-lint-results.xml && yarn lint:md:ci && yarn check-copyright-headers - store_test_results: path: reports/junit diff --git a/CHANGELOG.md b/CHANGELOG.md index 257e66b24706..ccfa03859ae9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -109,6 +109,7 @@ - `[docs]` Remove duplicate code in `MockFunctions` ([#7297](https://github.com/facebook/jest/pull/7297)) - `[jest-worker]` Standardize filenames ([#7316](https://github.com/facebook/jest/pull/7316)) - `[pretty-format]` Standardize filenames ([#7316](https://github.com/facebook/jest/pull/7316)) +- `[*]` Add check for Facebook copyright headers on CI ([#7370](https://github.com/facebook/jest/pull/7370)) ### Performance diff --git a/package.json b/package.json index 238af5ff7b8a..987d4eb37f73 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "flow-bin": "^0.85.0", "glob": "^7.1.1", "graceful-fs": "^4.1.11", + "isbinaryfile": "^3.0.3", "istanbul-api": "^1.3.1", "istanbul-lib-coverage": "^1.0.0", "jasmine-reporters": "^2.2.0", @@ -81,6 +82,7 @@ "scripts": { "build-clean": "rm -rf ./packages/*/build ./packages/*/build-es5", "build": "node ./scripts/build.js", + "check-copyright-headers": "node ./scripts/checkCopyrightHeaders.js", "clean-all": "rm -rf ./node_modules && rm -rf ./packages/*/node_modules && yarn clean-e2e && yarn build-clean", "clean-e2e": "find ./e2e -not \\( -path ./e2e/presets/js -prune \\) -not \\( -path ./e2e/presets/json -prune \\) -mindepth 2 -type d \\( -name node_modules -prune \\) -exec rm -r '{}' +", "jest": "node ./packages/jest-cli/bin/jest.js", diff --git a/scripts/checkCopyrightHeaders.js b/scripts/checkCopyrightHeaders.js new file mode 100755 index 000000000000..43ecbc7c7388 --- /dev/null +++ b/scripts/checkCopyrightHeaders.js @@ -0,0 +1,148 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +const fs = require('fs'); +const {execSync} = require('child_process'); +const isbinaryfile = require('isbinaryfile'); + +const getFileContents = path => fs.readFileSync(path, {encoding: 'utf-8'}); +const isDirectory = path => fs.lstatSync(path).isDirectory(); +const createRegExp = pattern => new RegExp(pattern); + +// Important: this patterns must be in sync with internal Facebook tools + +const GENERIC_IGNORED_EXTENSIONS = [ + 'lock', + 'patch', + 'exe', + 'bin', + 'cfg', + 'config', + 'conf', + 'html', + 'md', + 'markdown', + 'opam', + 'osm', + 'descr', + 'rst', + 'json', + 'key', + 'ini', + 'plist', + 'snap', + 'svg', + 'txt', + 'xcodeproj', + 'xcscheme', + 'xml', + 'yaml', + 'yml', + 'textile', + 'tsv', + 'csv', + 'pem', + 'csr', + 'der', + 'crt', + 'cert', + 'cer', + 'p7b', + 'iml', + 'org', + 'podspec', + 'modulemap', + 'pch', + 'lproj', + 'xcworkspace', + 'storyboard', + 'tvml', + 'xib', + 'pbxproj', + 'xcworkspacedata', + 'xccheckout', + 'xcsettings', + 'strings', + 'ipynb', + 'htm', + 'toml', +].map(extension => createRegExp(`\.${extension}$`)); + +const GENERIC_IGNORED_PATTERNS = [ + '(^|/)\\.[^/]+(/|$)', + + 'third[_\\-. ]party/', + '^node[_\\-. ]modules/', + 'gradlew\\.bat$', + 'gradlew$', + 'gradle/wrapper/', + '.idea/', + '__init__\\.py$', + '^Setup.hs$', + '^(readme|README|Readme)\\..*$', + 'Cargo\\.toml$', + '^Cartfile.*$', + '^.*\\.xcodeproj/$', + '^.*\\.xcworkspace/$', + '^.*\\.lproj/$', + '^.*\\.bundle/$', + '^MANIFEST\\.in$', +].map(createRegExp); + +const CUSTOM_IGNORED_PATTERNS = [ + '\\.(example|map)$', + '^examples/.*', + '^flow-typed/.*', + '^packages/expect/src/jasmineUtils\\.js$', + '^packages/jest-config/src/vendor/jsonlint\\.js$', +].map(createRegExp); + +const IGNORED_PATTERNS = [ + ...GENERIC_IGNORED_EXTENSIONS, + ...GENERIC_IGNORED_PATTERNS, + ...CUSTOM_IGNORED_PATTERNS, +]; + +const INCLUDED_PATTERNS = [ + // Any file with an extension + /\.[^/]+$/, +]; + +const COPYRIGHT_HEADER_RE = /(Facebook, Inc(.|,)? and its affiliates)|([0-9]{4}-present(.|,)? Facebook)|([0-9]{4}(.|,)? Facebook)/; + +function needsCopyrightHeader(file) { + const contents = getFileContents(file); + return contents.trim().length > 0 && !COPYRIGHT_HEADER_RE.test(contents); +} + +function check() { + const allFiles = execSync('git ls-files', {encoding: 'utf-8'}) + .trim() + .split('\n'); + + const invalidFiles = allFiles.filter( + file => + INCLUDED_PATTERNS.some(pattern => pattern.test(file)) && + !IGNORED_PATTERNS.some(pattern => pattern.test(file)) && + !isDirectory(file) && + !isbinaryfile.sync(file) && + needsCopyrightHeader(file) + ); + + if (invalidFiles.length > 0) { + console.log(`Facebook copyright header check failed for the following files: + + ${invalidFiles.join('\n ')} + +Please include the header or blacklist the files in \`scripts/checkCopyrightHeaders.js\``); + process.exit(1); + } +} + +check(); diff --git a/yarn.lock b/yarn.lock index 6e6fb15d740c..cfe08495395d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7819,7 +7819,7 @@ isarray@^2.0.4: resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.4.tgz#38e7bcbb0f3ba1b7933c86ba1894ddfc3781bbb7" integrity sha512-GMxXOiUirWg1xTKRipM0Ek07rX+ubx4nNVElTJdNLYmNO/2YrDkgJGw9CljXn+r4EWiDQg/8lsRdHyg2PJuUaA== -isbinaryfile@^3.0.0: +isbinaryfile@^3.0.0, isbinaryfile@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-3.0.3.tgz#5d6def3edebf6e8ca8cae9c30183a804b5f8be80" integrity sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw==