From d7629e13ed2c1d9e5fbfe4c177a2880533ba0eaf Mon Sep 17 00:00:00 2001 From: Alexander Lisianoi Date: Mon, 3 Jul 2017 02:26:39 +0200 Subject: [PATCH 1/9] Add getProjectPath() to compute path to parent project Previously, process.cwd() did the job just fine but with node v8.1.2 (compared to 7.10.0 at least) the output has changed. So, use the following hack: when installing a node package, npm adds it to PATH. Since we know: a) the suffix of that path entry (commitplease/node_modules/.bin) b) the fact that the other project is installing commitplease then find that entry and use its prefix as parent project path Refs: https://github.com/jquery/jquery/issues/3708 --- index.js | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 6876263..8d1e5fc 100644 --- a/index.js +++ b/index.js @@ -10,9 +10,37 @@ var validate = require('./lib/validate') var sanitize = require('./lib/sanitize') var defaults = require('./lib/defaults') +// Need to find the path to the project that is installing +// commitplease. Previously, process.cwd() made the job easy but its +// output changed with node v8.1.2 +function getProjectPath () { + // Use the fact that npm will inject a path that ends with + // commitplease/node_modules/.bin into PATH + var p = process.env.PATH.split(':').filter( + function (p) { + return p.endsWith(path.join('commitplease', 'node_modules', '.bin')) + } + ) + + if (p.length !== 1) { + console.error(chalk.red('Failed to find project path\n')) + } + + // Removing suffix node_modules/commitplease/node_modules/.bin will + // give the absolute path to the project root + p = p[0].split(path.sep) + p = p.slice(0, p.length - 4) + + return path.sep + p.join(path.sep) +} + function getOptions () { - var pkg = path.join(process.cwd(), 'package.json') - var npm = path.join(process.cwd(), '.npmrc') + var projectPath = getProjectPath() + + console.log(projectPath) + + var pkg = path.join(projectPath, 'package.json') + var npm = path.join(projectPath, '.npmrc') pkg = fs.existsSync(pkg) && require(pkg) || {} npm = fs.existsSync(npm) && ini.parse(fs.readFileSync(npm, 'utf8')) || {} From 67f5ab1df48fd423ce0c0f1cba24d0bb2d5de535 Mon Sep 17 00:00:00 2001 From: Alexander Lisianoi Date: Mon, 3 Jul 2017 09:10:15 +0200 Subject: [PATCH 2/9] Add ends-with dependency to make it work on node 0.12 --- index.js | 12 +++++++----- package.json | 1 + 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/index.js b/index.js index 8d1e5fc..f80058e 100644 --- a/index.js +++ b/index.js @@ -4,6 +4,7 @@ var path = require('path') var chalk = require('chalk') var Git = require('git-tools') +var endsWith = require('ends-with') var objectAssign = require('object-assign') var validate = require('./lib/validate') @@ -12,18 +13,21 @@ var defaults = require('./lib/defaults') // Need to find the path to the project that is installing // commitplease. Previously, process.cwd() made the job easy but its -// output changed with node v8.1.2 +// output changed with node v8.1.2 (at least compared to 7.10.0) function getProjectPath () { // Use the fact that npm will inject a path that ends with - // commitplease/node_modules/.bin into PATH + // commitplease/node_modules/.bin into process.env.PATH var p = process.env.PATH.split(':').filter( function (p) { - return p.endsWith(path.join('commitplease', 'node_modules', '.bin')) + return endsWith(p, path.join('commitplease', 'node_modules', '.bin')) } ) if (p.length !== 1) { console.error(chalk.red('Failed to find project path\n')) + + // Just leave with zero so as not to interrupt install + process.exit(0) } // Removing suffix node_modules/commitplease/node_modules/.bin will @@ -37,8 +41,6 @@ function getProjectPath () { function getOptions () { var projectPath = getProjectPath() - console.log(projectPath) - var pkg = path.join(projectPath, 'package.json') var npm = path.join(projectPath, '.npmrc') diff --git a/package.json b/package.json index 692b442..0345e60 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ }, "dependencies": { "chalk": "^1.1.1", + "ends-with": "^1.0.1", "git-tools": "^0.2.1", "ini": "^1.3.4", "object-assign": "^4.1.0", From 7c428fbf487faafbe0c407e6bd8d2423103b6e63 Mon Sep 17 00:00:00 2001 From: Alexander Lisianoi Date: Mon, 3 Jul 2017 10:11:00 +0200 Subject: [PATCH 3/9] Add sliceEnvPath to reuse the slicing hack in 2 places: - during install, look for `node_modules/commitplease/node_modules/.bin` - during usual trigger, look for `node_modules/.bin` --- index.js | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/index.js b/index.js index f80058e..b9988c5 100644 --- a/index.js +++ b/index.js @@ -11,31 +11,44 @@ var validate = require('./lib/validate') var sanitize = require('./lib/sanitize') var defaults = require('./lib/defaults') +function sliceEnvPath (suffix) { + var p = process.env.PATH.split(':').filter( + function (p) {return endsWith(p, suffix)} + ) + + if (p.length === 1) { + p = p[0].split(path.sep) + + p = p.slice(0, p.length - suffix.split(path.sep).length) + return p.join(path.sep) + } + + return undefined +} + // Need to find the path to the project that is installing // commitplease. Previously, process.cwd() made the job easy but its // output changed with node v8.1.2 (at least compared to 7.10.0) function getProjectPath () { // Use the fact that npm will inject a path that ends with // commitplease/node_modules/.bin into process.env.PATH - var p = process.env.PATH.split(':').filter( - function (p) { - return endsWith(p, path.join('commitplease', 'node_modules', '.bin')) - } + var p = sliceEnvPath( + path.join('node_modules', 'commitplease', 'node_modules', '.bin') ) - if (p.length !== 1) { - console.error(chalk.red('Failed to find project path\n')) - - // Just leave with zero so as not to interrupt install - process.exit(0) + if (p !== undefined) { + return p } - // Removing suffix node_modules/commitplease/node_modules/.bin will - // give the absolute path to the project root - p = p[0].split(path.sep) - p = p.slice(0, p.length - 4) + // Try a less specific suffix: + p = sliceEnvPath(path.join('node_modules', '.bin')) + + if (p !== undefined) { + return p + } - return path.sep + p.join(path.sep) + console.error(chalk.red('Could not find project path')) + process.exit(0) } function getOptions () { From 89138b5f09d9780e60ca54a49ca3b47f55264d52 Mon Sep 17 00:00:00 2001 From: Alexander Lisianoi Date: Tue, 18 Jul 2017 10:55:43 +0200 Subject: [PATCH 4/9] Drop node 0.12, add node 6 LTS Boron --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 842d7e7..a2404be 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ sudo: false language: node_js node_js: - - '0.12' # Legacy - - '4' # LTS + - '4' # LTS Argon + - '6' # LTS Boron - 'stable' From 4ab781a13e4690874f052735f3ad793a62b9e454 Mon Sep 17 00:00:00 2001 From: Alexander Lisianoi Date: Tue, 18 Jul 2017 11:08:10 +0200 Subject: [PATCH 5/9] Drop ends-with and object-assign dependencies --- index.js | 11 ++++------- package.json | 2 -- test.js | 10 ++++------ 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/index.js b/index.js index b9988c5..5e30c20 100644 --- a/index.js +++ b/index.js @@ -4,16 +4,13 @@ var path = require('path') var chalk = require('chalk') var Git = require('git-tools') -var endsWith = require('ends-with') -var objectAssign = require('object-assign') - var validate = require('./lib/validate') var sanitize = require('./lib/sanitize') var defaults = require('./lib/defaults') function sliceEnvPath (suffix) { var p = process.env.PATH.split(':').filter( - function (p) {return endsWith(p, suffix)} + function (p) {return p.endsWith(suffix)} ) if (p.length === 1) { @@ -63,7 +60,7 @@ function getOptions () { pkg = pkg.commitplease || {} npm = npm.commitplease || {} - var options = objectAssign(pkg, npm) + var options = Object.assign(pkg, npm) var base = { 'oldMessagePath': defaults.oldMessagePath, @@ -73,9 +70,9 @@ function getOptions () { if (options === undefined || options.style === undefined || options.style === 'jquery') { - return objectAssign(base, defaults.jquery, options) + return Object.assign(base, defaults.jquery, options) } else if (options.style === 'angular') { - return objectAssign(base, defaults.angular, options) + return Object.assign(base, defaults.angular, options) } console.error(chalk.red( diff --git a/package.json b/package.json index 0345e60..4f6dd17 100644 --- a/package.json +++ b/package.json @@ -36,10 +36,8 @@ }, "dependencies": { "chalk": "^1.1.1", - "ends-with": "^1.0.1", "git-tools": "^0.2.1", "ini": "^1.3.4", - "object-assign": "^4.1.0", "semver": "^5.1.0" } } diff --git a/test.js b/test.js index 26682ba..dfabc90 100644 --- a/test.js +++ b/test.js @@ -2,8 +2,6 @@ var validate = require('./lib/validate') var sanitize = require('./lib/sanitize') var defaults = require('./lib/defaults') -var objectAssign = require('object-assign') - var jqueryColon = 'First line must be : \n' + 'Missing colon :' @@ -32,22 +30,22 @@ var jqueryFirstLine72 = var jquery0 = defaults.jquery -var jquery1 = objectAssign( +var jquery1 = Object.assign( {}, defaults.jquery, {component: false} ) -var jquery2 = objectAssign( +var jquery2 = Object.assign( {}, defaults.jquery, {components: ['Build', 'Legacy']} ) -var jquery3 = objectAssign( +var jquery3 = Object.assign( {}, defaults.jquery, { markerPattern: '^((clos|fix|resolv)(e[sd]|ing))|^(refs?)', ticketPattern: '^((Closes|Fixes) ([a-zA-Z]{2,}-)[0-9]+)|^(Refs? [^#])' } ) -var jquery4 = objectAssign( +var jquery4 = Object.assign( {}, defaults.jquery, {components: ['^\\[\\w+-\\d+\\]']} ) From d6b39d06f2e92bcc05062af25af0c44709dfee65 Mon Sep 17 00:00:00 2001 From: Alexander Lisianoi Date: Tue, 18 Jul 2017 12:00:26 +0200 Subject: [PATCH 6/9] Improve getProjectPath and reuse it in install.js Commitplease is called by either npm or git which in turn supply different process.cwd() information. Use custom getProjectPath() function to more reliably determine where the project is actually located. --- index.js | 15 ++++++++++----- install.js | 16 +++++++++------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/index.js b/index.js index 5e30c20..f5f509a 100644 --- a/index.js +++ b/index.js @@ -23,11 +23,11 @@ function sliceEnvPath (suffix) { return undefined } -// Need to find the path to the project that is installing +// Need to find the path to the project that is installing or running // commitplease. Previously, process.cwd() made the job easy but its // output changed with node v8.1.2 (at least compared to 7.10.0) function getProjectPath () { - // Use the fact that npm will inject a path that ends with + // During npm install, npm will inject a path that ends with // commitplease/node_modules/.bin into process.env.PATH var p = sliceEnvPath( path.join('node_modules', 'commitplease', 'node_modules', '.bin') @@ -37,15 +37,19 @@ function getProjectPath () { return p } - // Try a less specific suffix: + // During npm run, npm will inject a path that ends with + // node_modules/.bin into process.env.PATH p = sliceEnvPath(path.join('node_modules', '.bin')) if (p !== undefined) { return p } - console.error(chalk.red('Could not find project path')) - process.exit(0) + // During git commit there will be no process.env.PATH modifications + // So, assume we are being run by git which will set process.cwd() + // to the root of the project as described in the manual: + // https://git-scm.com/docs/githooks/2.9.0 + return process.cwd() } function getOptions () { @@ -63,6 +67,7 @@ function getOptions () { var options = Object.assign(pkg, npm) var base = { + 'projectPath': projectPath, 'oldMessagePath': defaults.oldMessagePath, 'oldMessageSeconds': defaults.oldMessageSeconds } diff --git a/install.js b/install.js index bbf4b7b..01befa2 100644 --- a/install.js +++ b/install.js @@ -29,17 +29,19 @@ function xmkdirSync (path, mode) { } } -var git = path.resolve(process.cwd(), '..', '..', '.git') -var hooks = path.join(git, 'hooks') +var git = path.join(options.projectPath, '.git') + +var dstHooksPath = path.join(options.projectPath, '.git', 'hooks') +var srcHooksPath = path.join(options.projectPath, 'node_modules', 'commitplease') xmkdirSync(git, parseInt('755', 8)) -xmkdirSync(hooks, parseInt('755', 8)) +xmkdirSync(dstHooksPath, parseInt('755', 8)) -var dstCommitHook = path.join(hooks, 'commit-msg') -var srcCommitHook = path.relative(hooks, 'commit-msg-hook.js') +var dstCommitHook = path.join(dstHooksPath, 'commit-msg') +var srcCommitHook = path.join(srcHooksPath, 'commit-msg-hook.js') -var dstPrepareHook = path.join(hooks, 'prepare-commit-msg') -var srcPrepareHook = path.relative(hooks, 'prepare-commit-msg-hook.js') +var dstPrepareHook = path.join(dstHooksPath, 'prepare-commit-msg') +var srcPrepareHook = path.join(srcHooksPath, 'prepare-commit-msg-hook.js') var dstHooks = [dstCommitHook, dstPrepareHook] var srcHooks = [srcCommitHook, srcPrepareHook] From 33a95dd6542b0697ee794a3f74c12b0563e72390 Mon Sep 17 00:00:00 2001 From: Alexander Lisianoi Date: Tue, 18 Jul 2017 12:03:59 +0200 Subject: [PATCH 7/9] 3.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4f6dd17..07ad0e7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "commitplease", - "version": "2.7.10", + "version": "3.0.0", "description": "Validates strings as commit messages", "main": "index.js", "bin": { From cf43fa8d918e78eb594357560fe00d037777948f Mon Sep 17 00:00:00 2001 From: Alexander Lisianoi Date: Tue, 18 Jul 2017 12:52:51 +0200 Subject: [PATCH 8/9] Add function description to sliceEnvPath --- index.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/index.js b/index.js index f5f509a..c2f34cc 100644 --- a/index.js +++ b/index.js @@ -8,6 +8,9 @@ var validate = require('./lib/validate') var sanitize = require('./lib/sanitize') var defaults = require('./lib/defaults') +// If there is a path in process.env.PATH that looks like this: +// path = prefix + suffix (where suffix is the function argument) +// then slice off the suffix and return the prefix, otherwise undefiend function sliceEnvPath (suffix) { var p = process.env.PATH.split(':').filter( function (p) {return p.endsWith(suffix)} From b81d9c15185290bfadc32b8413e5c464a881aae1 Mon Sep 17 00:00:00 2001 From: Alexander Lisianoi Date: Tue, 18 Jul 2017 12:53:12 +0200 Subject: [PATCH 9/9] Add early opt-out if commitplease is being self-installed --- install.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/install.js b/install.js index 01befa2..2c4534a 100644 --- a/install.js +++ b/install.js @@ -4,8 +4,17 @@ var chalk = require('chalk') var options = require('./index.js').getOptions() -if (options && options.nohook) { - console.log('commitplease: package.json or .npmrc set to skip hook') +// Is this a self-install? If so, do not copy hooks and quit early +var pkgPath = path.join(options.projectPath, 'package.json') +var pkg = fs.existsSync(pkgPath) && require(pkgPath) + +if (pkg && pkg.name && pkg.name === 'commitplease') { + console.log('commitplease: self-install detected, skipping hooks') + process.exit(0) +} + +if (options.nohook) { + console.log('commitplease: package.json or .npmrc set to skip hooks') process.exit(0) }