1'use strict' 2 3var fs = require('fs') 4var path = require('path') 5var resolve = path.resolve 6var mkdirp = require('mkdirp') 7var rimraf = require('rimraf') 8var test = require('tap').test 9var npm = require('../../lib/npm') 10var common = require('../common-tap') 11var chain = require('slide').chain 12 13var mockPath = common.pkg 14var parentPath = resolve(mockPath, 'parent') 15var parentNodeModulesPath = path.join(parentPath, 'node_modules') 16var outdatedNodeModulesPath = resolve(mockPath, 'node-modules-backup') 17var childPath = resolve(mockPath, 'child.git') 18 19var gitDaemon 20var gitDaemonPID 21var git 22 23var parentPackageJSON = JSON.stringify({ 24 name: 'parent', 25 version: '0.1.0' 26}) 27 28var childPackageJSON = JSON.stringify({ 29 name: 'child', 30 version: '0.1.0' 31}) 32 33test('setup', function (t) { 34 mkdirp.sync(parentPath) 35 fs.writeFileSync(resolve(parentPath, 'package.json'), parentPackageJSON) 36 process.chdir(parentPath) 37 38 // Setup child 39 mkdirp.sync(childPath) 40 fs.writeFileSync(resolve(childPath, 'package.json'), childPackageJSON) 41 42 // Setup npm and then git 43 npm.load({ 44 registry: common.registry, 45 loglevel: 'silent', 46 save: true // Always install packages with --save 47 }, function () { 48 // It's important to initialize git after npm because it uses config 49 initializeGit(function (err, result) { 50 t.ifError(err, 'git started up successfully') 51 52 if (!err) { 53 gitDaemon = result[result.length - 2] 54 gitDaemonPID = result[result.length - 1] 55 } 56 57 t.end() 58 }) 59 }) 60}) 61 62test('shrinkwrapped git dependency got updated', function (t) { 63 t.comment('test for https://github.com/npm/npm/issues/12718') 64 65 // Prepare the child package git repo with two commits 66 prepareChildAndGetRefs(function (err, refs) { 67 if (err) { throw err } 68 chain([ 69 // Install & shrinkwrap child package's first commit 70 [npm.commands.install, ['git://localhost:' + common.gitPort + '/child.git#' + refs[0]]], 71 // Backup node_modules with the first commit 72 [fs.rename, parentNodeModulesPath, outdatedNodeModulesPath], 73 // Install & shrinkwrap child package's latest commit 74 [npm.commands.install, ['git://localhost:' + common.gitPort + '/child.git#' + refs[1].substr(0, 8)]], 75 // Restore node_modules with the first commit 76 [rimraf, parentNodeModulesPath], 77 [fs.rename, outdatedNodeModulesPath, parentNodeModulesPath], 78 // Update node_modules 79 [npm.commands.install, []] 80 ], function () { 81 const pkglock = require(path.join(parentPath, 'package-lock.json')) 82 t.similar(pkglock, { 83 dependencies: { 84 child: { 85 version: `git://localhost:${common.gitPort}/child.git#${refs[1]}`, 86 from: `git://localhost:${common.gitPort}/child.git#${refs[1].substr(0, 8)}` 87 } 88 } 89 }, 'version and from fields are correct in git-based pkglock dep') 90 var childPackageJSON = require(path.join(parentNodeModulesPath, 'child', 'package.json')) 91 t.equal( 92 childPackageJSON._resolved, 93 'git://localhost:' + common.gitPort + '/child.git#' + refs[1], 94 "Child package wasn't updated" 95 ) 96 t.end() 97 }) 98 }) 99}) 100 101test('clean', function (t) { 102 gitDaemon.on('close', t.end) 103 process.kill(gitDaemonPID) 104}) 105 106function prepareChildAndGetRefs (cb) { 107 var opts = { cwd: childPath, env: { PATH: process.env.PATH } } 108 chain([ 109 [fs.writeFile, path.join(childPath, 'README.md'), ''], 110 git.chainableExec(['add', 'README.md'], opts), 111 git.chainableExec(['commit', '-m', 'Add README'], opts), 112 git.chainableExec(['log', '--pretty=format:"%H"', '-2'], opts) 113 ], function (err) { 114 if (err) { return cb(err) } 115 var gitLogStdout = arguments[arguments.length - 1] 116 var refs = gitLogStdout[gitLogStdout.length - 1].split('\n').map(function (ref) { 117 return ref.match(/^"(.+)"$/)[1] 118 }).reverse() // Reverse refs order: last, first -> first, last 119 cb(null, refs) 120 }) 121} 122 123function initializeGit (cb) { 124 git = require('../../lib/utils/git') 125 common.makeGitRepo({ 126 path: childPath, 127 commands: [startGitDaemon] 128 }, cb) 129} 130 131function startGitDaemon (cb) { 132 var daemon = git.spawn( 133 [ 134 'daemon', 135 '--verbose', 136 '--listen=localhost', 137 '--export-all', 138 '--base-path=' + mockPath, // Path to the dir that contains child.git 139 '--reuseaddr', 140 '--port=' + common.gitPort 141 ], 142 { 143 cwd: parentPath, 144 env: process.env, 145 stdio: ['pipe', 'pipe', 'pipe'] 146 } 147 ) 148 daemon.stderr.on('data', function findChild (c) { 149 var cpid = c.toString().match(/^\[(\d+)\]/) 150 if (cpid[1]) { 151 this.removeListener('data', findChild) 152 cb(null, [daemon, cpid[1]]) 153 } 154 }) 155} 156