diff --git a/.editorconfig b/.editorconfig index 88f50f5aef..62fcd43244 100644 --- a/.editorconfig +++ b/.editorconfig @@ -4,7 +4,7 @@ insert_final_newline = true trim_trailing_whitespace = true indent_style = tab -[{.*rc,*.yml,*.md,package.json,*.svg}] +[{.*rc,*.yml,*.md,package.json,lerna.json,*.svg}] indent_style = space [*.md] diff --git a/.travis.yml b/.travis.yml index 12a95059b0..aeefbf6b1f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,12 +6,13 @@ node_js: install: - npm install -g npx - npx yarn install - - npx lerna bootstrap --since $TRAVIS_BRANCH --include-filtered-dependencies --stream + - npx lerna bootstrap - npm --version - yarn --version - npx --version script: - - npx yarn build --since $TRAVIS_BRANCH --include-filtered-dependencies --stream - - npx yarn lint --since $TRAVIS_BRANCH --include-filtered-dependencies --stream - - npx yarn deps --since $TRAVIS_BRANCH --include-filtered-dependencies --stream - - npx yarn test --since $TRAVIS_BRANCH --include-filtered-dependencies --stream + - npx yarn build + - node @commitlint/travis-cli/lib/cli.js + - npx yarn lint + - npx yarn deps + - npx yarn test diff --git a/@commitlint/cli/index.js b/@commitlint/cli/index.js new file mode 100644 index 0000000000..6babb12a58 --- /dev/null +++ b/@commitlint/cli/index.js @@ -0,0 +1,3 @@ +const path = require('path'); + +module.exports = path.join(__dirname, 'lib/cli.js'); diff --git a/@commitlint/cli/package.json b/@commitlint/cli/package.json index 447ffdc969..b15f2f0de1 100644 --- a/@commitlint/cli/package.json +++ b/@commitlint/cli/package.json @@ -6,13 +6,13 @@ "commitlint": "./lib/cli.js" }, "scripts": { - "build": "npx cross-env NODE_ENV=production npx -p babel-cli babel src --out-dir lib --source-maps", + "build": "cross-env NODE_ENV=production babel src --out-dir lib --source-maps", "clean": "npx rimraf lib", "deps": "dep-check", - "lint": "npx xo", - "start": "npx concurrently \"npx ava -c 4 --verbose --watch\" \"npx yarn run watch\"", - "test": "npx ava -c 4 --verbose", - "watch": "npx -p babel-cli babel src --out-dir lib --watch --source-maps" + "lint": "xo", + "start": "concurrently \"ava -c 4 --verbose --watch\" \"yarn run watch\"", + "test": "ava -c 4 --verbose", + "watch": "babel src --out-dir lib --watch --source-maps" }, "ava": { "files": [ diff --git a/@commitlint/config-angular-type-enum/package.json b/@commitlint/config-angular-type-enum/package.json index d06dd39c37..a976a621de 100644 --- a/@commitlint/config-angular-type-enum/package.json +++ b/@commitlint/config-angular-type-enum/package.json @@ -5,7 +5,7 @@ "scripts": { "clean": "exit 0", "deps": "dep-check", - "lint": "npx xo", + "lint": "xo", "start": "exit 0", "test": "exit 0" }, diff --git a/@commitlint/config-angular/package.json b/@commitlint/config-angular/package.json index 9d38537118..1e272acc2b 100644 --- a/@commitlint/config-angular/package.json +++ b/@commitlint/config-angular/package.json @@ -5,7 +5,7 @@ "scripts": { "clean": "exit 0", "deps": "dep-check", - "lint": "npx xo", + "lint": "xo", "start": "exit 0", "test": "exit 0" }, diff --git a/@commitlint/config-lerna-scopes/package.json b/@commitlint/config-lerna-scopes/package.json index bf8d758e5a..8d9b36baed 100644 --- a/@commitlint/config-lerna-scopes/package.json +++ b/@commitlint/config-lerna-scopes/package.json @@ -4,9 +4,9 @@ "description": "Shareable commitlint config enforcing lerna package names as scopes", "scripts": { "clean": "exit 0", - "lint": "npx xo", - "start": "npx ava --watch --verbose", - "test": "npx ava --verbose" + "lint": "xo", + "start": "ava --watch --verbose", + "test": "ava --verbose" }, "xo": false, "ava": { diff --git a/@commitlint/config-patternplate/package.json b/@commitlint/config-patternplate/package.json index d20b50934d..d82bf4ec6d 100644 --- a/@commitlint/config-patternplate/package.json +++ b/@commitlint/config-patternplate/package.json @@ -5,7 +5,7 @@ "scripts": { "clean": "exit 0", "deps": "dep-check", - "lint": "npx xo", + "lint": "xo", "start": "exit 0", "test": "exit 0" }, diff --git a/@commitlint/core/package.json b/@commitlint/core/package.json index f482372c7f..ee46fe6bdb 100644 --- a/@commitlint/core/package.json +++ b/@commitlint/core/package.json @@ -4,13 +4,13 @@ "description": "Lint your commit messages", "main": "lib/index.js", "scripts": { - "build": "npx cross-env NODE_ENV=production npx -p babel-cli babel src --out-dir lib --source-maps", + "build": "cross-env NODE_ENV=production babel src --out-dir lib --source-maps", "clean": "npx rimraf lib", "deps": "dep-check", - "lint": "npx xo", - "start": "npx concurrently \"npx ava -c 4 --verbose --watch\" \"npx yarn run watch\"", - "test": "npx ava -c 4 --verbose && npx ava \"src/*.serial-test.js\" --verbose", - "watch": "npx -p babel-cli babel src --out-dir lib --watch --source-maps" + "lint": "xo", + "start": "concurrently \"ava -c 4 --verbose --watch\" \"yarn run watch\"", + "test": "ava -c 4 --verbose && ava \"src/*.serial-test.js\" --verbose", + "watch": "babel src --out-dir lib --watch --source-maps" }, "ava": { "files": [ diff --git a/@commitlint/prompt-cli/package.json b/@commitlint/prompt-cli/package.json index b199ab99d6..95ca851b85 100644 --- a/@commitlint/prompt-cli/package.json +++ b/@commitlint/prompt-cli/package.json @@ -9,7 +9,7 @@ "clean": "npx rimraf lib", "commit": "$npm_package_bin_commit", "deps": "dep-check", - "lint": "npx xo" + "lint": "xo" }, "xo": false, "repository": { diff --git a/@commitlint/prompt/package.json b/@commitlint/prompt/package.json index 57065edbfc..19c5553d3d 100644 --- a/@commitlint/prompt/package.json +++ b/@commitlint/prompt/package.json @@ -4,14 +4,14 @@ "description": "commitizen prompt using commitlint.config.js", "main": "./lib/index.js", "scripts": { - "build": "npx cross-env NODE_ENV=production npx -p babel-cli babel src --out-dir lib --source-maps", + "build": "cross-env NODE_ENV=production babel src --out-dir lib --source-maps", "clean": "npx rimraf lib", - "commit": "npx git-cz", + "commit": "git-cz", "deps": "dep-check", - "lint": "npx xo", - "start": "npx concurrently \"npx ava --watch --verbose\" \"npx yarn run watch\"", - "test": "npx ava --verbose", - "watch": "npx -p babel-cli babel src --out-dir lib --watch --source-maps" + "lint": "xo", + "start": "concurrently \"ava --watch --verbose\" \"yarn run watch\"", + "test": "ava --verbose", + "watch": "babel src --out-dir lib --watch --source-maps" }, "ava": { "babel": "inherit", diff --git a/@commitlint/travis-cli/README.md b/@commitlint/travis-cli/README.md new file mode 100644 index 0000000000..a85348bf77 --- /dev/null +++ b/@commitlint/travis-cli/README.md @@ -0,0 +1,19 @@ +> Lint all relevant commits for a change or PR on Travis CI + +# @commitlint/travis-cli + +This package is a convenience wrapper around `commitlint`, +providing zero-configuration linting of all relevant commits +for a given change/build combination. + +## Getting started + +``` +npm install --save-dev @commitlint/travis-cli +``` + +```yml +# .travis.yml +script + - commitlint-travis +``` diff --git a/@commitlint/travis-cli/fixtures/commitlint.js b/@commitlint/travis-cli/fixtures/commitlint.js new file mode 100755 index 0000000000..333349df2e --- /dev/null +++ b/@commitlint/travis-cli/fixtures/commitlint.js @@ -0,0 +1,2 @@ +#!/usr/bin/env node +console.log(process.argv); diff --git a/@commitlint/travis-cli/fixtures/git.js b/@commitlint/travis-cli/fixtures/git.js new file mode 100755 index 0000000000..333349df2e --- /dev/null +++ b/@commitlint/travis-cli/fixtures/git.js @@ -0,0 +1,2 @@ +#!/usr/bin/env node +console.log(process.argv); diff --git a/@commitlint/travis-cli/package.json b/@commitlint/travis-cli/package.json new file mode 100644 index 0000000000..a6002ad80f --- /dev/null +++ b/@commitlint/travis-cli/package.json @@ -0,0 +1,72 @@ +{ + "name": "@commitlint/travis-cli", + "version": "5.0.1", + "description": "Lint all relevant commits for a change or PR on Travis CI", + "bin": { + "commitlint-travis": "./lib/cli.js" + }, + "scripts": { + "build": "cross-env NODE_ENV=production babel src --out-dir lib --source-maps", + "clean": "npx rimraf lib", + "deps": "dep-check", + "lint": "xo", + "start": "ava -c 4 --verbose --watch", + "test": "ava -c 4 --verbose", + "watch": "babel src --out-dir lib --watch --source-maps" + }, + "ava": { + "files": [ + "src/**/*.test.js" + ], + "source": [ + "lib/**/*.js" + ], + "babel": "inherit", + "require": [ + "babel-register" + ] + }, + "babel": { + "presets": [ + "babel-preset-commitlint" + ] + }, + "xo": false, + "engines": { + "node": ">=4" + }, + "repository": { + "type": "git", + "url": "https://github.com/marionebl/commitlint.git" + }, + "bugs": { + "url": "https://github.com/marionebl/commitlint/issues" + }, + "homepage": "https://github.com/marionebl/commitlint#readme", + "keywords": [ + "conventional-changelog", + "commitlint", + "cli" + ], + "author": { + "name": "Mario Nebl", + "email": "hello@herebecode.com" + }, + "license": "MIT", + "devDependencies": { + "@commitlint/utils": "^5.0.1", + "@commitlint/test": "^5.0.1", + "ava": "0.18.2", + "babel-cli": "6.26.0", + "babel-preset-commitlint": "^5.0.1", + "babel-register": "6.26.0", + "cross-env": "5.1.1", + "which": "^1.3.0" + }, + "dependencies": { + "@commitlint/cli": "^5.0.1", + "@marionebl/sander": "^0.6.1", + "execa": "^0.8.0", + "find-up": "^2.1.0" + } +} diff --git a/@commitlint/travis-cli/src/cli.js b/@commitlint/travis-cli/src/cli.js new file mode 100755 index 0000000000..8ab5184c4f --- /dev/null +++ b/@commitlint/travis-cli/src/cli.js @@ -0,0 +1,78 @@ +#!/usr/bin/env node +const sander = require('@marionebl/sander'); +const execa = require('execa'); +const findUp = require('find-up'); + +// Allow to override used bins for testing purposes +const GIT = process.env.TRAVIS_COMMITLINT_GIT_BIN || 'git'; +const COMMITLINT = + process.env.TRAVIS_COMMITLINT_BIN || require('@commitlint/cli'); // eslint-disable-line import/newline-after-import +const REQUIRED = ['TRAVIS_COMMIT', 'TRAVIS_BRANCH']; + +const TRAVIS_BRANCH = process.env.TRAVIS_BRANCH; +const TRAVIS_COMMIT = process.env.TRAVIS_COMMIT; + +main().catch(err => { + console.log(err); + process.exit(1); +}); + +async function main() { + if (process.env.CI !== 'true' || process.env.TRAVIS !== 'true') { + throw new Error( + `@commitlint/travis-cli is inteded to be used on Travis CI` + ); + } + + const gitRoot = await findUp('.git'); + const missing = REQUIRED.filter(envVar => !(envVar in process.env)); + + if (missing.length > 0) { + const stanza = missing.length > 1 ? 'they were not' : 'it was not'; + throw new Error( + `Expected ${missing.join(', ')} to be defined globally, ${stanza}.` + ); + } + + const pop = await stash(); + + await git(['remote', 'set-branches', 'origin', TRAVIS_BRANCH]); + + if (await sander.exists(gitRoot, 'shallow')) { + await git(['fetch', '--unshallow', '--quiet']); + } + + await git(['checkout', TRAVIS_BRANCH, '--quiet']); + await git(['checkout', '-', '--quiet']); + + await pop(); + + await lint(['--from', TRAVIS_BRANCH, '--to', TRAVIS_COMMIT]); +} + +async function git(args, options) { + return execa(GIT, args, Object.assign({}, {stdio: 'inherit'}, options)); +} + +async function isClean() { + const result = await git(['status', '--porcelain'], { + stdio: ['pipe', 'pipe', 'pipe'] + }); + return !(result.stdout && result.stdout.trim()); +} + +async function lint(args, options) { + return execa( + COMMITLINT, + args, + Object.assign({}, {stdio: 'inherit'}, options) + ); +} + +async function stash() { + if (await isClean()) { + return async () => {}; + } + await git(['stash']); + return () => git(['stash', 'pop']); +} diff --git a/@commitlint/travis-cli/src/cli.test.js b/@commitlint/travis-cli/src/cli.test.js new file mode 100644 index 0000000000..dcda393d24 --- /dev/null +++ b/@commitlint/travis-cli/src/cli.test.js @@ -0,0 +1,204 @@ +const os = require('os'); +const {git} = require('@commitlint/test'); +const test = require('ava'); +const execa = require('execa'); +const which = require('which'); + +const NODE_BIN = which.sync('node'); +const BIN = require.resolve('../lib/cli.js'); + +const TRAVIS_COMMITLINT_BIN = require.resolve('../fixtures/commitlint'); +const TRAVIS_COMMITLINT_GIT_BIN = require.resolve('../fixtures/git'); +const TRAVIS_BRANCH = 'TRAVIS_BRANCH'; +const TRAVIS_COMMIT = 'TRAVIS_COMMIT'; + +const bin = async (config = {}) => { + try { + return await execa(BIN, Object.assign({extendEnv: false}, config)); + } catch (err) { + throw new Error([err.stdout, err.stderr].join('\n')); + } +}; + +test('should throw when not on travis ci', async t => { + const env = { + CI: false, + TRAVIS: false + }; + + await t.throws( + bin({env}), + /@commitlint\/travis-cli is inteded to be used on Travis CI/ + ); +}); + +test('should throw when on travis ci, but env vars are missing', async t => { + const env = { + TRAVIS: true, + CI: true + }; + + await t.throws(bin({env}), /TRAVIS_COMMIT, TRAVIS_BRANCH/); +}); + +test('should throw when on travis ci, but TRAVIS_COMMIT is missing', async t => { + const env = { + TRAVIS: true, + CI: true + }; + + await t.throws(bin({env}), /TRAVIS_COMMIT/); +}); + +test('should throw when on travis ci, but TRAVIS_BRANCH is missing', async t => { + const env = { + TRAVIS: true, + CI: true + }; + + await t.throws(bin({env}), /TRAVIS_BRANCH/); +}); + +test('should call git with expected args on shallow repo', async t => { + if (os.platform() === 'win32') { + t.pass(); + return; + } + + const cwd = await git.clone('https://github.com/marionebl/commitlint.git', [ + '--depth=10' + ]); + + const env = { + TRAVIS: true, + CI: true, + TRAVIS_BRANCH, + TRAVIS_COMMIT, + TRAVIS_COMMITLINT_BIN, + TRAVIS_COMMITLINT_GIT_BIN + }; + + const result = await bin({cwd, env}); + const invocations = await getInvocations(result.stdout); + t.is(invocations.length, 7); + + const [ + stash, + branches, + unshallow, + checkout, + back, + pop, + commilint + ] = invocations; + + t.deepEqual(stash, [NODE_BIN, TRAVIS_COMMITLINT_GIT_BIN, 'stash']); + t.deepEqual(branches, [ + NODE_BIN, + TRAVIS_COMMITLINT_GIT_BIN, + 'remote', + 'set-branches', + 'origin', + TRAVIS_BRANCH + ]); + t.deepEqual(unshallow, [ + NODE_BIN, + TRAVIS_COMMITLINT_GIT_BIN, + 'fetch', + '--unshallow', + '--quiet' + ]); + t.deepEqual(checkout, [ + NODE_BIN, + TRAVIS_COMMITLINT_GIT_BIN, + 'checkout', + TRAVIS_BRANCH, + '--quiet' + ]); + t.deepEqual(back, [ + NODE_BIN, + TRAVIS_COMMITLINT_GIT_BIN, + 'checkout', + '-', + '--quiet' + ]); + t.deepEqual(pop, [NODE_BIN, TRAVIS_COMMITLINT_GIT_BIN, 'stash', 'pop']); + t.deepEqual(commilint, [ + NODE_BIN, + TRAVIS_COMMITLINT_BIN, + '--from', + TRAVIS_BRANCH, + '--to', + TRAVIS_COMMIT + ]); +}); + +test('should call git with expected args on unshallow repo', async t => { + if (os.platform() === 'win32') { + t.pass(); + return; + } + + const cwd = await git.clone('https://github.com/marionebl/commitlint.git'); + + const env = { + TRAVIS: true, + CI: true, + TRAVIS_BRANCH, + TRAVIS_COMMIT, + TRAVIS_COMMITLINT_BIN, + TRAVIS_COMMITLINT_GIT_BIN + }; + + const result = await bin({cwd, env}); + const invocations = await getInvocations(result.stdout); + t.is(invocations.length, 6); + + const [stash, branches, checkout, back, pop, commilint] = invocations; + + t.deepEqual(stash, [NODE_BIN, TRAVIS_COMMITLINT_GIT_BIN, 'stash']); + t.deepEqual(branches, [ + NODE_BIN, + TRAVIS_COMMITLINT_GIT_BIN, + 'remote', + 'set-branches', + 'origin', + TRAVIS_BRANCH + ]); + t.deepEqual(checkout, [ + NODE_BIN, + TRAVIS_COMMITLINT_GIT_BIN, + 'checkout', + TRAVIS_BRANCH, + '--quiet' + ]); + t.deepEqual(back, [ + NODE_BIN, + TRAVIS_COMMITLINT_GIT_BIN, + 'checkout', + '-', + '--quiet' + ]); + t.deepEqual(pop, [NODE_BIN, TRAVIS_COMMITLINT_GIT_BIN, 'stash', 'pop']); + t.deepEqual(commilint, [ + NODE_BIN, + TRAVIS_COMMITLINT_BIN, + '--from', + TRAVIS_BRANCH, + '--to', + TRAVIS_COMMIT + ]); +}); + +function getInvocations(stdout) { + const matches = stdout.match(/[^[\]]+/g); + const raw = Array.isArray(matches) ? matches : []; + + return raw.filter(invocation => invocation !== '\n').map(invocation => + invocation + .split(',') + .map(fragment => fragment.trim()) + .map(fragment => fragment.substring(1, fragment.length - 1)) + .filter(Boolean) + ); +} diff --git a/@packages/babel-preset-commitlint/package.json b/@packages/babel-preset-commitlint/package.json index b2c31bf7ec..58cbacfafa 100644 --- a/@packages/babel-preset-commitlint/package.json +++ b/@packages/babel-preset-commitlint/package.json @@ -5,9 +5,9 @@ "main": "index.js", "scripts": { "deps": "dep-check", - "lint": "npx xo", - "start": "npx ava --watch --verbose", - "test": "npx ava --verbose" + "lint": "xo", + "start": "ava --watch --verbose", + "test": "ava --verbose" }, "ava": { "files": [ diff --git a/@packages/test/package.json b/@packages/test/package.json index 7c7ed756a9..560b35714f 100644 --- a/@packages/test/package.json +++ b/@packages/test/package.json @@ -5,13 +5,13 @@ "main": "lib/", "private": true, "scripts": { - "build": "npx cross-env NODE_ENV=production npx -p babel-cli babel src --out-dir lib --source-maps", + "build": "cross-env NODE_ENV=production babel src --out-dir lib --source-maps", "clean": "npx rimraf lib", "deps": "dep-check", - "lint": "npx xo", - "start": "npx concurrently \"npx ava --watch --verbose\" \"npx yarn run watch\"", - "test": "npx ava --verbose", - "watch": "npx -p babel-cli babel src --out-dir lib --watch --source-maps" + "lint": "xo", + "start": "concurrently \"ava --watch --verbose\" \"yarn run watch\"", + "test": "ava --verbose", + "watch": "babel src --out-dir lib --watch --source-maps" }, "ava": { "files": [ diff --git a/@packages/utils/package.json b/@packages/utils/package.json index 0ac7d2ae17..399164de8f 100644 --- a/@packages/utils/package.json +++ b/@packages/utils/package.json @@ -4,7 +4,7 @@ "description": "Development utilities for @commitlint", "bin": { "dep-check": "./dep-check.js", - "lint": "npx xo" + "lint": "xo" }, "scripts": { "build": "exit 0", diff --git a/package.json b/package.json index bb9e5be3ca..3a8079b214 100644 --- a/package.json +++ b/package.json @@ -5,18 +5,18 @@ "version": "1.0.0", "license": "MIT", "scripts": { - "build": "npx lerna run build --stream --parallel --include-filtered-dependencies", + "build": "lerna run build --stream --parallel --include-filtered-dependencies", "clean": "npx lerna clean --yes && npx lerna run clean --stream --parallel --include-filtered-dependencies", - "commit": "npx -p @commitlint/prompt-cli commit", - "commitmsg": "npx commitlint -e $GIT_PARAMS", - "deps": "npx lerna run deps", - "docs": "npx docsify serve docs", - "lint": "npx lerna run lint", + "commit": "node @commitlint/prompt-cli/cli.js", + "commitmsg": "node @commitlint/cli/lib/cli.js -e $GIT_PARAMS", + "deps": "lerna run deps", + "docs": "docsify serve docs", + "lint": "lerna run lint", "precommit": "lint-staged", - "publish": "npx lerna publish --conventional-commits", - "reinstall": "npm run clean && npm install", - "start": "npx lerna run start --stream --parallel --include-filtered-dependencies", - "test": "npx lerna run test --stream --parallel --include-filtered-dependencies" + "publish": "lerna publish --conventional-commits", + "reinstall": "yarn clean && yarn install", + "start": "lerna run start --stream --parallel --include-filtered-dependencies", + "test": "lerna run test --stream --parallel --include-filtered-dependencies" }, "commitlint": { "extends": [ diff --git a/yarn.lock b/yarn.lock index a5c04da3f9..85f8a61079 100644 --- a/yarn.lock +++ b/yarn.lock @@ -81,7 +81,7 @@ split2 "^2.0.0" through2 "^2.0.0" -"@marionebl/sander@0.6.1", "@marionebl/sander@^0.6.0": +"@marionebl/sander@0.6.1", "@marionebl/sander@^0.6.0", "@marionebl/sander@^0.6.1": version "0.6.1" resolved "https://registry.npmjs.org/@marionebl/sander/-/sander-0.6.1.tgz#1958965874f24bc51be48875feb50d642fc41f7b" dependencies: @@ -6999,7 +6999,7 @@ which-module@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" -which@1, which@^1.2.10, which@^1.2.12, which@^1.2.14, which@^1.2.9: +which@1, which@^1.2.10, which@^1.2.12, which@^1.2.14, which@^1.2.9, which@^1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" dependencies: