-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathspawn.js
148 lines (141 loc) · 4.13 KB
/
spawn.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
const spawn = require('../lib/spawn.js')
const errors = require('../lib/errors.js')
const t = require('tap')
t.rejects(spawn(['status'], { git: false }), {
message: 'No git binary found in $PATH',
code: 'ENOGIT',
})
const slash = require('slash')
const { resolve } = require('path')
const repo = t.testdir()
const fs = require('fs')
// init a repo. this also tests the happy path and default options
t.test('setup repo', t => {
const cwd = process.cwd()
t.teardown(() => process.chdir(cwd))
process.chdir(repo)
return t.resolveMatch(spawn(['init']),
{ stdout: `Initialized empty Git repository in ${slash(fs.realpathSync.native(repo))}` })
})
t.test('argument test for allowReplace', async t => {
// Note: the *actual* impact of allowReplace:true is tested in
// test/clone.js, since it covers the use case that is relevant
// for our purposes. This just tests that the argument is added
// by default.
const mockedSpawn = t.mock('../lib/spawn.js', {
'@npmcli/promise-spawn': async (exe, args) => args,
})
const [allow, deny, allowWithArg, denyWithArg] = await Promise.all([
mockedSpawn(['a', 'b', 'c'], { allowReplace: true }),
mockedSpawn(['a', 'b', 'c']),
mockedSpawn(['--no-replace-objects', 'a', 'b', 'c'], { allowReplace: true }),
mockedSpawn(['--no-replace-objects', 'a', 'b', 'c']),
])
t.same(allow, ['a', 'b', 'c'], 'replacements allowed')
t.same(deny, ['--no-replace-objects', 'a', 'b', 'c'], 'replacements not allowed')
t.same(allowWithArg, ['--no-replace-objects', 'a', 'b', 'c'], 'allowed by config, not pruned out')
t.same(denyWithArg, ['--no-replace-objects', 'a', 'b', 'c'], 'denied by config, not duplicated')
})
t.test('retries', t => {
const logs = []
process.on('log', (...log) => logs.push(log))
const gitMessage = 'Connection timed out'
const te = resolve(repo, 'transient-error.js')
fs.writeFileSync(te, `
console.error('${gitMessage.trim()}')
process.exit(1)
`)
const retryOptions = {
'one retry object': {
retry: {
retries: 2,
factor: 1,
maxTimeout: 1000,
minTimeout: 1,
},
},
'namespaced fetchRetry* configs': {
fetchRetries: 2,
fetchRetryFactor: 1,
fetchRetryMaxtimeout: 1000,
fetchRetryMintimeout: 1,
},
}
const er = Object.assign(new errors.GitConnectionError(gitMessage), {
cmd: process.execPath,
args: [te],
code: 1,
signal: null,
stdout: '',
stderr: gitMessage,
message: 'A git connection error occurred',
})
Object.keys(retryOptions).forEach(n => t.test(n, async t => {
await t.rejects(spawn([te], {
cwd: repo,
git: process.execPath,
allowReplace: true,
...(retryOptions[n]),
}), er)
t.same(logs, [
[
'silly',
'git',
`Retrying git command: ${te} attempt # 2`,
],
[
'silly',
'git',
`Retrying git command: ${te} attempt # 3`,
],
], 'got expected logs')
logs.length = 0
}))
t.end()
})
t.test('missing pathspec', t => {
const gitMessage = 'error: pathspec \'foo\' did not match any file(s) known to git'
const te = resolve(repo, 'pathspec-error.js')
fs.writeFileSync(te, `
console.error("${gitMessage.trim()}")
process.exit(1)
`)
const er = Object.assign(new errors.GitPathspecError(gitMessage), {
cmd: process.execPath,
args: [te],
code: 1,
signal: null,
stdout: '',
stderr: gitMessage,
message: 'The git reference could not be found',
})
t.rejects(spawn([te], {
cwd: repo,
git: process.execPath,
allowReplace: true,
}), er)
t.end()
})
t.test('unknown git error', t => {
const gitMessage = 'error: something really bad happened to git'
const te = resolve(repo, 'unknown-error.js')
fs.writeFileSync(te, `
console.error("${gitMessage.trim()}")
process.exit(1)
`)
const er = Object.assign(new errors.GitUnknownError(gitMessage), {
cmd: process.execPath,
args: [te],
code: 1,
signal: null,
stdout: '',
stderr: gitMessage,
message: 'An unknown git error occurred',
})
t.rejects(spawn([te], {
cwd: repo,
git: process.execPath,
allowReplace: true,
}), er)
t.end()
})