• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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