release-it 19.0.0-next.0 → 19.0.0-next.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/test/git.js CHANGED
@@ -1,414 +1,409 @@
1
+ import test, { beforeEach, describe } from 'node:test';
2
+ import assert from 'node:assert/strict';
1
3
  import { EOL } from 'node:os';
2
4
  import childProcess from 'node:child_process';
3
5
  import { appendFileSync } from 'node:fs';
4
- import test from 'ava';
5
- import sinon from 'sinon';
6
6
  import Git from '../lib/plugin/git/Git.js';
7
7
  import { execOpts, touch } from '../lib/util.js';
8
8
  import sh from './util/sh.js';
9
9
  import { factory } from './util/index.js';
10
10
  import { mkTmpDir, readFile, gitAdd } from './util/helpers.js';
11
11
 
12
- test.beforeEach(() => {
13
- const tmp = mkTmpDir();
14
- process.chdir(tmp);
15
- });
16
-
17
- test.serial('should return whether repo has upstream branch', async t => {
18
- const gitClient = factory(Git);
19
- childProcess.execSync('git init', execOpts);
20
- gitAdd('line', 'file', 'Add file');
21
- t.false(await gitClient.hasUpstreamBranch());
22
- });
12
+ describe('git', () => {
13
+ beforeEach(() => {
14
+ const tmp = mkTmpDir();
15
+ process.chdir(tmp);
16
+ });
23
17
 
24
- test.serial('should return branch name', async t => {
25
- const gitClient = factory(Git);
26
- childProcess.execSync('git init', execOpts);
27
- t.is(await gitClient.getBranchName(), null);
28
- childProcess.execSync('git checkout -b feat', execOpts);
29
- gitAdd('line', 'file', 'Add file');
30
- t.is(await gitClient.getBranchName(), 'feat');
31
- });
18
+ test('should return whether repo has upstream branch', async () => {
19
+ const gitClient = factory(Git);
20
+ childProcess.execSync('git init', execOpts);
21
+ gitAdd('line', 'file', 'Add file');
22
+ assert.equal(await gitClient.hasUpstreamBranch(), false);
23
+ });
32
24
 
33
- test.serial('should return whether tag exists and if working dir is clean', async t => {
34
- const gitClient = factory(Git);
35
- childProcess.execSync('git init', execOpts);
36
- t.false(await gitClient.tagExists('1.0.0'));
37
- touch('file');
38
- t.false(await gitClient.isWorkingDirClean());
39
- gitAdd('line', 'file', 'Add file');
40
- childProcess.execSync('git tag 1.0.0', execOpts);
41
- t.true(await gitClient.tagExists('1.0.0'));
42
- t.true(await gitClient.isWorkingDirClean());
43
- });
25
+ test('should return branch name', async () => {
26
+ const gitClient = factory(Git);
27
+ childProcess.execSync('git init', execOpts);
28
+ assert.equal(await gitClient.getBranchName(), null);
29
+ childProcess.execSync('git checkout -b feat', execOpts);
30
+ gitAdd('line', 'file', 'Add file');
31
+ assert.equal(await gitClient.getBranchName(), 'feat');
32
+ });
44
33
 
45
- test.serial('should throw if tag exists', async t => {
46
- const gitClient = factory(Git);
47
- childProcess.execSync('git init', execOpts);
48
- touch('file');
49
- gitAdd('line', 'file', 'Add file');
50
- childProcess.execSync('git tag 0.0.2', execOpts);
51
- gitClient.config.setContext({ latestTag: '0.0.1', tagName: '0.0.2' });
52
- const expected = { instanceOf: Error, message: /fatal: tag '0\.0\.2' already exists/ };
53
- await t.throwsAsync(gitClient.tag({ name: '0.0.2' }), expected);
54
- });
34
+ test('should return whether tag exists and if working dir is clean', async () => {
35
+ const gitClient = factory(Git);
36
+ childProcess.execSync('git init', execOpts);
37
+ assert.equal(await gitClient.tagExists('1.0.0'), false);
38
+ touch('file');
39
+ assert.equal(await gitClient.isWorkingDirClean(), false);
40
+ gitAdd('line', 'file', 'Add file');
41
+ childProcess.execSync('git tag 1.0.0', execOpts);
42
+ assert(await gitClient.tagExists('1.0.0'));
43
+ assert(await gitClient.isWorkingDirClean());
44
+ });
55
45
 
56
- test.serial('should only warn if tag exists intentionally', async t => {
57
- const gitClient = factory(Git);
58
- const { warn } = gitClient.log;
59
- childProcess.execSync('git init', execOpts);
60
- touch('file');
61
- gitAdd('line', 'file', 'Add file');
62
- childProcess.execSync('git tag 1.0.0', execOpts);
63
- gitClient.config.setContext({ latestTag: '1.0.0', tagName: '1.0.0' });
64
- await t.notThrowsAsync(gitClient.tag());
65
- t.is(warn.callCount, 1);
66
- t.is(warn.firstCall.args[0], 'Tag "1.0.0" already exists');
67
- });
46
+ test('should throw if tag exists', async () => {
47
+ const gitClient = factory(Git);
48
+ childProcess.execSync('git init', execOpts);
49
+ touch('file');
50
+ gitAdd('line', 'file', 'Add file');
51
+ childProcess.execSync('git tag 0.0.2', execOpts);
52
+ gitClient.config.setContext({ latestTag: '0.0.1', tagName: '0.0.2' });
53
+ await assert.rejects(gitClient.tag({ name: '0.0.2' }), /fatal: tag '0\.0\.2' already exists/);
54
+ });
68
55
 
69
- test.serial('should return the remote url', async t => {
70
- childProcess.execSync(`git init`, execOpts);
71
- {
72
- const options = { git: { pushRepo: 'origin' } };
73
- const gitClient = factory(Git, { options });
74
- t.is(await gitClient.getRemoteUrl(), null);
75
- childProcess.execSync(`git remote add origin foo`, execOpts);
76
- t.is(await gitClient.getRemoteUrl(), 'foo');
77
- }
78
- {
79
- const options = { git: { pushRepo: 'another' } };
80
- const gitClient = factory(Git, { options });
81
- t.is(await gitClient.getRemoteUrl(), null);
82
- childProcess.execSync(`git remote add another bar`, execOpts);
83
- t.is(await gitClient.getRemoteUrl(), 'bar');
84
- }
85
- {
86
- const options = { git: { pushRepo: 'git://github.com/webpro/release-it.git' } };
87
- const gitClient = factory(Git, { options });
88
- t.is(await gitClient.getRemoteUrl(), 'git://github.com/webpro/release-it.git');
89
- }
90
- });
56
+ test('should only warn if tag exists intentionally', async t => {
57
+ const gitClient = factory(Git);
58
+ const warn = t.mock.method(gitClient.log, 'warn');
59
+ childProcess.execSync('git init', execOpts);
60
+ touch('file');
61
+ gitAdd('line', 'file', 'Add file');
62
+ childProcess.execSync('git tag 1.0.0', execOpts);
63
+ gitClient.config.setContext({ latestTag: '1.0.0', tagName: '1.0.0' });
64
+ await assert.doesNotReject(gitClient.tag());
65
+ assert.equal(warn.mock.callCount(), 1);
66
+ assert.equal(warn.mock.calls[0].arguments[0], 'Tag "1.0.0" already exists');
67
+ });
91
68
 
92
- test.serial('should return the non-origin remote', async t => {
93
- const bare = mkTmpDir();
94
- childProcess.execSync(`git init --bare ${bare}`, execOpts);
95
- childProcess.execSync(`git clone ${bare} .`, execOpts);
96
- gitAdd('line', 'file', 'Add file');
97
- childProcess.execSync('git remote rename origin upstream', execOpts);
98
- const gitClient = factory(Git);
99
- t.is(await gitClient.getRemoteUrl(), bare);
100
- });
69
+ test('should return the remote url', async () => {
70
+ childProcess.execSync(`git init`, execOpts);
71
+ {
72
+ const options = { git: { pushRepo: 'origin' } };
73
+ const gitClient = factory(Git, { options });
74
+ assert.equal(await gitClient.getRemoteUrl(), null);
75
+ childProcess.execSync(`git remote add origin foo`, execOpts);
76
+ assert.equal(await gitClient.getRemoteUrl(), 'foo');
77
+ }
78
+ {
79
+ const options = { git: { pushRepo: 'another' } };
80
+ const gitClient = factory(Git, { options });
81
+ assert.equal(await gitClient.getRemoteUrl(), null);
82
+ childProcess.execSync(`git remote add another bar`, execOpts);
83
+ assert.equal(await gitClient.getRemoteUrl(), 'bar');
84
+ }
85
+ {
86
+ const options = { git: { pushRepo: 'git://github.com/webpro/release-it.git' } };
87
+ const gitClient = factory(Git, { options });
88
+ assert.equal(await gitClient.getRemoteUrl(), 'git://github.com/webpro/release-it.git');
89
+ }
90
+ });
101
91
 
102
- test.serial('should stage, commit, tag and push', async t => {
103
- const bare = mkTmpDir();
104
- childProcess.execSync(`git init --bare ${bare}`, execOpts);
105
- childProcess.execSync(`git clone ${bare} .`, execOpts);
106
- const version = '1.2.3';
107
- gitAdd(`{"version":"${version}"}`, 'package.json', 'Add package.json');
108
- {
109
- const gitClient = factory(Git);
110
- childProcess.execSync(`git tag ${version}`, execOpts);
111
- t.is(await gitClient.getLatestTagName(), version);
112
- }
113
- {
92
+ test('should return the non-origin remote', async () => {
93
+ const bare = mkTmpDir();
94
+ childProcess.execSync(`git init --bare ${bare}`, execOpts);
95
+ childProcess.execSync(`git clone ${bare} .`, execOpts);
96
+ gitAdd('line', 'file', 'Add file');
97
+ childProcess.execSync('git remote rename origin upstream', execOpts);
114
98
  const gitClient = factory(Git);
99
+ assert.equal(await gitClient.getRemoteUrl(), bare);
100
+ });
101
+
102
+ test('should stage, commit, tag and push', async () => {
103
+ const bare = mkTmpDir();
104
+ childProcess.execSync(`git init --bare ${bare}`, execOpts);
105
+ childProcess.execSync(`git clone ${bare} .`, execOpts);
106
+ const version = '1.2.3';
107
+ gitAdd(`{"version":"${version}"}`, 'package.json', 'Add package.json');
108
+ {
109
+ const gitClient = factory(Git);
110
+ childProcess.execSync(`git tag ${version}`, execOpts);
111
+ assert.equal(await gitClient.getLatestTagName(), version);
112
+ }
113
+ {
114
+ const gitClient = factory(Git);
115
+ gitAdd('line', 'file', 'Add file');
116
+ childProcess.execSync('npm --no-git-tag-version version patch', execOpts);
117
+ await gitClient.stage('package.json');
118
+ await gitClient.commit({ message: `Release v1.2.4` });
119
+ await gitClient.tag({ name: 'v1.2.4', annotation: 'Release v1.2.4' });
120
+ assert.equal(await gitClient.getLatestTagName(), 'v1.2.4');
121
+ await gitClient.push();
122
+ const stdout = childProcess.execSync('git status -uno', { encoding: 'utf-8' });
123
+ assert.match(stdout, /nothing to commit/);
124
+ }
125
+ });
126
+
127
+ test('should commit, tag and push with extra args', async t => {
128
+ const bare = mkTmpDir();
129
+ childProcess.execSync(`git init --bare ${bare}`, execOpts);
130
+ childProcess.execSync(`git clone ${bare} .`, execOpts);
115
131
  gitAdd('line', 'file', 'Add file');
116
- childProcess.execSync('npm --no-git-tag-version version patch', execOpts);
132
+ const options = { git: { commitArgs: '-S', tagArgs: ['-T', 'foo'], pushArgs: ['-U', 'bar', '-V'] } };
133
+ const gitClient = factory(Git, { options });
134
+ const stub = t.mock.method(gitClient.shell, 'exec', () => Promise.resolve());
117
135
  await gitClient.stage('package.json');
118
136
  await gitClient.commit({ message: `Release v1.2.4` });
119
137
  await gitClient.tag({ name: 'v1.2.4', annotation: 'Release v1.2.4' });
120
- t.is(await gitClient.getLatestTagName(), 'v1.2.4');
121
138
  await gitClient.push();
122
- const stdout = childProcess.execSync('git status -uno', { encoding: 'utf-8' });
123
-
124
- t.true(stdout.includes('nothing to commit'));
125
- }
126
- });
139
+ assert(stub.mock.calls[1].arguments[0].includes('-S'));
140
+ assert.equal(stub.mock.calls[2].arguments[0][5], '-T');
141
+ assert.equal(stub.mock.calls[2].arguments[0][6], 'foo');
142
+ assert(stub.mock.calls.at(-1).arguments[0].join(' ').includes('-U bar -V'));
143
+ });
127
144
 
128
- test.serial('should commit, tag and push with extra args', async t => {
129
- const bare = mkTmpDir();
130
- childProcess.execSync(`git init --bare ${bare}`, execOpts);
131
- childProcess.execSync(`git clone ${bare} .`, execOpts);
132
- gitAdd('line', 'file', 'Add file');
133
- const options = { git: { commitArgs: '-S', tagArgs: ['-T', 'foo'], pushArgs: ['-U', 'bar', '-V'] } };
134
- const gitClient = factory(Git, { options });
135
- const stub = sinon.stub(gitClient.shell, 'exec').resolves();
136
- await gitClient.stage('package.json');
137
- await gitClient.commit({ message: `Release v1.2.4` });
138
- await gitClient.tag({ name: 'v1.2.4', annotation: 'Release v1.2.4' });
139
- await gitClient.push();
140
- t.true(stub.secondCall.args[0].includes('-S'));
141
- t.is(stub.thirdCall.args[0][5], '-T');
142
- t.is(stub.thirdCall.args[0][6], 'foo');
143
- t.true(stub.lastCall.args[0].join(' ').includes('-U bar -V'));
144
- stub.restore();
145
- });
145
+ test('should amend commit without message if not provided', async t => {
146
+ const bare = mkTmpDir();
147
+ childProcess.execSync(`git init --bare ${bare}`, execOpts);
148
+ childProcess.execSync(`git clone ${bare} .`, execOpts);
149
+ gitAdd('line', 'file', 'Add file');
150
+ const options = { git: { commitArgs: ['--amend', '--no-edit', '--no-verify'] } };
151
+ const gitClient = factory(Git, { options });
152
+ const exec = t.mock.method(gitClient.shell, 'exec', () => Promise.resolve());
153
+ await gitClient.stage('package.json');
154
+ await gitClient.commit();
155
+ assert.deepEqual(exec.mock.calls[1].arguments[0], ['git', 'commit', '--amend', '--no-edit', '--no-verify']);
156
+ });
146
157
 
147
- test.serial('should amend commit without message if not provided', async t => {
148
- const bare = mkTmpDir();
149
- childProcess.execSync(`git init --bare ${bare}`, execOpts);
150
- childProcess.execSync(`git clone ${bare} .`, execOpts);
151
- gitAdd('line', 'file', 'Add file');
152
- const options = { git: { commitArgs: ['--amend', '--no-edit', '--no-verify'] } };
153
- const gitClient = factory(Git, { options });
154
- const stub = sinon.stub(gitClient.shell, 'exec').resolves();
155
- await gitClient.stage('package.json');
156
- await gitClient.commit();
157
- t.deepEqual(stub.secondCall.args[0], ['git', 'commit', '--amend', '--no-edit', '--no-verify']);
158
- stub.restore();
159
- });
158
+ test('should commit and tag with quoted characters', async () => {
159
+ const bare = mkTmpDir();
160
+ childProcess.execSync(`git init --bare ${bare}`, execOpts);
161
+ childProcess.execSync(`git clone ${bare} .`, execOpts);
162
+ const gitClient = factory(Git, {
163
+ options: { git: { commitMessage: 'Release ${version}', tagAnnotation: 'Release ${version}\n\n${changelog}' } }
164
+ });
165
+ touch('file');
166
+ const changelog = `- Foo's${EOL}- "$bar"${EOL}- '$baz'${EOL}- foo`;
167
+ gitClient.config.setContext({ version: '1.0.0', changelog });
168
+
169
+ await gitClient.stage('file');
170
+ await gitClient.commit();
171
+ await gitClient.tag({ name: '1.0.0' });
172
+ await gitClient.push();
173
+ {
174
+ const stdout = childProcess.execSync('git log -1 --format=%s', { encoding: 'utf-8' });
175
+ assert.equal(stdout.trim(), 'Release 1.0.0');
176
+ }
177
+ {
178
+ const stdout = childProcess.execSync('git tag -n99', { encoding: 'utf-8' });
179
+ assert.equal(
180
+ stdout.trim(),
181
+ `1.0.0 Release 1.0.0\n \n - Foo's\n - "$bar"\n - '$baz'\n - foo`
182
+ );
183
+ }
184
+ });
160
185
 
161
- test.serial('should commit and tag with quoted characters', async t => {
162
- const bare = mkTmpDir();
163
- childProcess.execSync(`git init --bare ${bare}`, execOpts);
164
- childProcess.execSync(`git clone ${bare} .`, execOpts);
165
- const gitClient = factory(Git, {
166
- options: { git: { commitMessage: 'Release ${version}', tagAnnotation: 'Release ${version}\n\n${changelog}' } }
186
+ test('should push to origin', async t => {
187
+ const bare = mkTmpDir();
188
+ childProcess.execSync(`git init --bare ${bare}`, execOpts);
189
+ childProcess.execSync(`git clone ${bare} .`, execOpts);
190
+ gitAdd('line', 'file', 'Add file');
191
+ const gitClient = factory(Git);
192
+ const spy = t.mock.method(gitClient.shell, 'exec');
193
+ await gitClient.push();
194
+ assert.deepEqual(spy.mock.calls.at(-1).arguments[0], ['git', 'push']);
195
+ const stdout = childProcess.execSync('git ls-tree -r HEAD --name-only', {
196
+ cwd: bare,
197
+ encoding: 'utf-8'
198
+ });
199
+ assert.equal(stdout.trim(), 'file');
167
200
  });
168
- touch('file');
169
- const changelog = `- Foo's${EOL}- "$bar"${EOL}- '$baz'${EOL}- foo`;
170
- gitClient.config.setContext({ version: '1.0.0', changelog });
171
-
172
- await gitClient.stage('file');
173
- await gitClient.commit();
174
- await gitClient.tag({ name: '1.0.0' });
175
- await gitClient.push();
176
- {
177
- const stdout = childProcess.execSync('git log -1 --format=%s', { encoding: 'utf-8' });
178
- t.is(stdout.trim(), 'Release 1.0.0');
179
- }
180
- {
181
- const stdout = childProcess.execSync('git tag -n99', { encoding: 'utf-8' });
182
- t.is(stdout.trim(), `1.0.0 Release 1.0.0\n \n - Foo's\n - "$bar"\n - '$baz'\n - foo`);
183
- }
184
- });
185
201
 
186
- test.serial('should push to origin', async t => {
187
- const bare = mkTmpDir();
188
- childProcess.execSync(`git init --bare ${bare}`, execOpts);
189
- childProcess.execSync(`git clone ${bare} .`, execOpts);
190
- gitAdd('line', 'file', 'Add file');
191
- const gitClient = factory(Git);
192
- const spy = sinon.spy(gitClient.shell, 'exec');
193
- await gitClient.push();
194
- t.deepEqual(spy.lastCall.args[0], ['git', 'push']);
195
- const stdout = childProcess.execSync('git ls-tree -r HEAD --name-only', {
196
- cwd: bare,
197
- encoding: 'utf-8'
202
+ test('should push to tracked upstream branch', async t => {
203
+ const bare = mkTmpDir();
204
+ childProcess.execSync(`git init --bare ${bare}`, execOpts);
205
+ childProcess.execSync(`git clone ${bare} .`, execOpts);
206
+ childProcess.execSync(`git remote rename origin upstream`, execOpts);
207
+ gitAdd('line', 'file', 'Add file');
208
+ const gitClient = factory(Git);
209
+ const spy = t.mock.method(gitClient.shell, 'exec');
210
+ await gitClient.push();
211
+ assert.deepEqual(spy.mock.calls.at(-1).arguments[0], ['git', 'push']);
212
+ const stdout = childProcess.execSync('git ls-tree -r HEAD --name-only', {
213
+ cwd: bare,
214
+ encoding: 'utf-8'
215
+ });
216
+ assert.equal(stdout.trim(), 'file');
198
217
  });
199
- t.is(stdout.trim(), 'file');
200
218
 
201
- spy.restore();
202
- });
219
+ test('should push to repo url', async t => {
220
+ const bare = mkTmpDir();
221
+ childProcess.execSync(`git init --bare ${bare}`, execOpts);
222
+ childProcess.execSync(`git clone ${bare} .`, execOpts);
223
+ gitAdd('line', 'file', 'Add file');
224
+ const options = { git: { pushRepo: 'https://host/repo.git' } };
225
+ const gitClient = factory(Git, { options });
226
+ const spy = t.mock.method(gitClient.shell, 'exec');
227
+ try {
228
+ await gitClient.push();
229
+ } catch (err) {
230
+ assert.deepEqual(spy.mock.calls.at(-1).arguments[0], ['git', 'push', 'https://host/repo.git']);
231
+ }
232
+ });
203
233
 
204
- test.serial('should push to tracked upstream branch', async t => {
205
- const bare = mkTmpDir();
206
- childProcess.execSync(`git init --bare ${bare}`, execOpts);
207
- childProcess.execSync(`git clone ${bare} .`, execOpts);
208
- childProcess.execSync(`git remote rename origin upstream`, execOpts);
209
- gitAdd('line', 'file', 'Add file');
210
- const gitClient = factory(Git);
211
- const spy = sinon.spy(gitClient.shell, 'exec');
212
- await gitClient.push();
213
- t.deepEqual(spy.lastCall.args[0], ['git', 'push']);
214
- const stdout = childProcess.execSync('git ls-tree -r HEAD --name-only', {
215
- cwd: bare,
216
- encoding: 'utf-8'
234
+ test('should push to remote name (not "origin")', async t => {
235
+ const bare = mkTmpDir();
236
+ childProcess.execSync(`git init --bare ${bare}`, execOpts);
237
+ childProcess.execSync(`git clone ${bare} .`, execOpts);
238
+ gitAdd('line', 'file', 'Add file');
239
+ childProcess.execSync(
240
+ `git remote add upstream ${childProcess.execSync('git config --get remote.origin.url', {
241
+ encoding: 'utf-8'
242
+ })}`,
243
+ execOpts
244
+ );
245
+ const options = { git: { pushRepo: 'upstream' } };
246
+ const gitClient = factory(Git, { options });
247
+ const spy = t.mock.method(gitClient.shell, 'exec');
248
+ await gitClient.push();
249
+ assert.deepEqual(spy.mock.calls.at(-1).arguments[0], ['git', 'push', 'upstream']);
250
+ const stdout = childProcess.execSync('git ls-tree -r HEAD --name-only', {
251
+ cwd: bare,
252
+ encoding: 'utf-8'
253
+ });
254
+ assert.equal(stdout.trim(), 'file');
255
+
256
+ {
257
+ childProcess.execSync(`git checkout -b foo`, execOpts);
258
+ gitAdd('line', 'file', 'Add file');
259
+ await gitClient.push();
260
+ assert.deepEqual(spy.mock.calls.at(-1).arguments[0], ['git', 'push', '--set-upstream', 'upstream', 'foo']);
261
+ assert.match(
262
+ await spy.mock.calls.at(-1).result,
263
+ /branch .?foo.? set up to track (remote branch .?foo.? from .?upstream.?|.?upstream\/foo.?)/i
264
+ );
265
+ }
217
266
  });
218
- t.is(stdout.trim(), 'file');
219
267
 
220
- spy.restore();
221
- });
268
+ test('should return repo status', async () => {
269
+ const gitClient = factory(Git);
270
+ childProcess.execSync('git init', execOpts);
271
+ gitAdd('line', 'file1', 'Add file');
222
272
 
223
- test.serial('should push to repo url', async t => {
224
- const bare = mkTmpDir();
225
- childProcess.execSync(`git init --bare ${bare}`, execOpts);
226
- childProcess.execSync(`git clone ${bare} .`, execOpts);
227
- gitAdd('line', 'file', 'Add file');
228
- const options = { git: { pushRepo: 'https://host/repo.git' } };
229
- const gitClient = factory(Git, { options });
230
- const spy = sinon.spy(gitClient.shell, 'exec');
231
- try {
232
- await gitClient.push();
233
- } catch (err) {
234
- t.deepEqual(spy.lastCall.args[0], ['git', 'push', 'https://host/repo.git']);
235
- }
236
- spy.restore();
237
- });
273
+ appendFileSync('file1', 'line');
238
274
 
239
- test.serial('should push to remote name (not "origin")', async t => {
240
- const bare = mkTmpDir();
241
- childProcess.execSync(`git init --bare ${bare}`, execOpts);
242
- childProcess.execSync(`git clone ${bare} .`, execOpts);
243
- gitAdd('line', 'file', 'Add file');
244
- childProcess.execSync(
245
- `git remote add upstream ${childProcess.execSync('git config --get remote.origin.url', {
246
- encoding: 'utf-8'
247
- })}`,
248
- execOpts
249
- );
250
- const options = { git: { pushRepo: 'upstream' } };
251
- const gitClient = factory(Git, { options });
252
- const spy = sinon.spy(gitClient.shell, 'exec');
253
- await gitClient.push();
254
- t.deepEqual(spy.lastCall.args[0], ['git', 'push', 'upstream']);
255
- const stdout = childProcess.execSync('git ls-tree -r HEAD --name-only', {
256
- cwd: bare,
257
- encoding: 'utf-8'
275
+ appendFileSync('file2', 'line');
276
+ childProcess.execSync('git add file2', execOpts);
277
+ assert.equal(await gitClient.status(), ' M file1\nA file2');
258
278
  });
259
- t.is(stdout.trim(), 'file');
260
279
 
261
- {
262
- childProcess.execSync(`git checkout -b foo`, execOpts);
280
+ test('should reset files', async t => {
281
+ const gitClient = factory(Git);
282
+ childProcess.execSync('git init', execOpts);
263
283
  gitAdd('line', 'file', 'Add file');
264
- await gitClient.push();
265
- t.deepEqual(spy.lastCall.args[0], ['git', 'push', '--set-upstream', 'upstream', 'foo']);
266
- t.regex(
267
- await spy.lastCall.returnValue,
268
- /branch .?foo.? set up to track (remote branch .?foo.? from .?upstream.?|.?upstream\/foo.?)/i
269
- );
270
- }
271
- spy.restore();
272
- });
273
284
 
274
- test.serial('should return repo status', async t => {
275
- const gitClient = factory(Git);
276
- childProcess.execSync('git init', execOpts);
277
- gitAdd('line', 'file1', 'Add file');
285
+ appendFileSync('file', 'line');
286
+ assert.match(await readFile('file'), /^line\s*line\s*$/);
287
+ await gitClient.reset('file');
288
+ assert.match(await readFile('file'), /^line\s*$/);
289
+ const warn = t.mock.method(gitClient.log, 'warn');
290
+ await gitClient.reset(['file2, file3']);
291
+ assert.match(warn.mock.calls[0].arguments[0], /Could not reset file2, file3/);
292
+ });
278
293
 
279
- appendFileSync('file1', 'line');
294
+ test('should roll back when cancelled', async t => {
295
+ childProcess.execSync('git init', execOpts);
296
+ childProcess.execSync(`git remote add origin file://foo`, execOpts);
297
+ const version = '1.2.3';
298
+ gitAdd(`{"version":"${version}"}`, 'package.json', 'Add package.json');
299
+ const options = { git: { requireCleanWorkingDir: true, commit: true, tag: true, tagName: 'v${version}' } };
300
+ const gitClient = factory(Git, { options });
301
+ const exec = t.mock.method(gitClient.shell, 'execFormattedCommand');
302
+ childProcess.execSync(`git tag ${version}`, execOpts);
303
+ gitAdd('line', 'file', 'Add file');
280
304
 
281
- appendFileSync('file2', 'line');
282
- childProcess.execSync('git add file2', execOpts);
283
- t.is(await gitClient.status(), ' M file1\nA file2');
284
- });
305
+ await gitClient.init();
285
306
 
286
- test.serial('should reset files', async t => {
287
- const gitClient = factory(Git);
288
- childProcess.execSync('git init', execOpts);
289
- gitAdd('line', 'file', 'Add file');
290
-
291
- appendFileSync('file', 'line');
292
- t.regex(await readFile('file'), /^line\s*line\s*$/);
293
- await gitClient.reset('file');
294
- t.regex(await readFile('file'), /^line\s*$/);
295
- await gitClient.reset(['file2, file3']);
296
- t.regex(gitClient.log.warn.firstCall.args[0], /Could not reset file2, file3/);
297
- });
307
+ childProcess.execSync('npm --no-git-tag-version version patch', execOpts);
298
308
 
299
- test.serial('should roll back when cancelled', async t => {
300
- childProcess.execSync('git init', execOpts);
301
- childProcess.execSync(`git remote add origin file://foo`, execOpts);
302
- const version = '1.2.3';
303
- gitAdd(`{"version":"${version}"}`, 'package.json', 'Add package.json');
304
- const options = { git: { requireCleanWorkingDir: true, commit: true, tag: true, tagName: 'v${version}' } };
305
- const gitClient = factory(Git, { options });
306
- const exec = sinon.spy(gitClient.shell, 'execFormattedCommand');
307
- childProcess.execSync(`git tag ${version}`, execOpts);
308
- gitAdd('line', 'file', 'Add file');
309
-
310
- await gitClient.init();
311
-
312
- childProcess.execSync('npm --no-git-tag-version version patch', execOpts);
313
-
314
- gitClient.bump('1.2.4');
315
- await gitClient.beforeRelease();
316
- await gitClient.stage('package.json');
317
- await gitClient.commit({ message: 'Add this' });
318
- await gitClient.tag();
319
- await gitClient.rollbackOnce();
320
-
321
- t.is(exec.args[11][0], 'git tag --delete v1.2.4');
322
- t.is(exec.args[12][0], 'git reset --hard HEAD~1');
323
- });
309
+ gitClient.bump('1.2.4');
310
+ await gitClient.beforeRelease();
311
+ await gitClient.stage('package.json');
312
+ await gitClient.commit({ message: 'Add this' });
313
+ await gitClient.tag();
314
+ await gitClient.rollbackOnce();
324
315
 
325
- // To get this test to pass, I had to switch between spawnsync and execsync somehow
326
- test.serial('should remove remote tag when push to branch failed', async t => {
327
- childProcess.execSync('git init', execOpts);
328
- childProcess.execSync(`git remote add origin file://foo`, execOpts);
329
- sh.exec(`git remote update`, execOpts);
330
- const version = '1.2.3';
331
- gitAdd(`{"version":"${version}"}`, 'package.json', 'Add package.json');
332
- const options = { git: { requireCleanWorkingDir: true, commit: true, tag: true, tagName: 'v${version}' } };
333
- const gitClient = factory(Git, { options });
334
- const exec = sinon.spy(gitClient.shell, 'execFormattedCommand');
335
- sh.exec(`git push`, execOpts);
336
- sh.exec(`git checkout HEAD~1`, execOpts);
337
- gitAdd('line', 'file', 'Add file');
338
-
339
- await gitClient.init();
340
-
341
- childProcess.execSync('npm --no-git-tag-version version patch', execOpts);
342
-
343
- gitClient.bump('1.2.4');
344
- await gitClient.beforeRelease();
345
- await gitClient.stage('package.json');
346
- await gitClient.commit({ message: 'Add this' });
347
- await gitClient.tag();
348
- try {
349
- await gitClient.push();
350
- } catch (e) {
351
- // push would fail with an error since HEAD is behind origin
352
- }
353
- t.is(exec.args[15][0], 'git push origin --delete v1.2.4');
354
- });
316
+ assert.equal(exec.mock.calls[11].arguments[0], 'git tag --delete v1.2.4');
317
+ assert.equal(exec.mock.calls[12].arguments[0], 'git reset --hard HEAD~1');
318
+ });
355
319
 
356
- test.serial('should not touch existing history when rolling back', async t => {
357
- childProcess.execSync('git init', execOpts);
358
- const version = '1.2.3';
359
- gitAdd(`{"version":"${version}"}`, 'package.json', 'Add package.json');
360
- const options = { git: { requireCleanWorkingDir: true, commit: true, tag: true } };
361
- const gitClient = factory(Git, { options });
362
- childProcess.execSync(`git tag ${version}`, execOpts);
363
-
364
- const exec = sinon.spy(gitClient.shell, 'execFormattedCommand');
365
- gitClient.config.setContext({ version: '1.2.4' });
366
- await gitClient.beforeRelease();
367
- await gitClient.commit();
368
- await gitClient.rollbackOnce();
369
-
370
- t.is(exec.args[3][0], 'git reset --hard HEAD');
371
- });
320
+ // To get this test to pass, I had to switch between spawnsync and execsync somehow
321
+ test('should remove remote tag when push to branch failed', async t => {
322
+ childProcess.execSync('git init', execOpts);
323
+ childProcess.execSync(`git remote add origin file://foo`, execOpts);
324
+ sh.exec(`git remote update`, execOpts);
325
+ const version = '1.2.3';
326
+ gitAdd(`{"version":"${version}"}`, 'package.json', 'Add package.json');
327
+ const options = { git: { requireCleanWorkingDir: true, commit: true, tag: true, tagName: 'v${version}' } };
328
+ const gitClient = factory(Git, { options });
329
+ const exec = t.mock.method(gitClient.shell, 'execFormattedCommand');
330
+ sh.exec(`git push`, execOpts);
331
+ sh.exec(`git checkout HEAD~1`, execOpts);
332
+ gitAdd('line', 'file', 'Add file');
372
333
 
373
- // eslint-disable-next-line ava/no-skip-test
374
- test.serial.skip('should not roll back with risky config', async t => {
375
- childProcess.execSync('git init', execOpts);
376
- const options = { git: { requireCleanWorkingDir: false, commit: true, tag: true } };
377
- const gitClient = factory(Git, { options });
378
- await gitClient.beforeRelease();
379
- t.is('rollbackOnce' in gitClient, false);
380
- });
334
+ await gitClient.init();
381
335
 
382
- test.serial('should return latest tag from default branch (not parent commit)', async t => {
383
- childProcess.execSync('git init', execOpts);
336
+ childProcess.execSync('npm --no-git-tag-version version patch', execOpts);
337
+
338
+ gitClient.bump('1.2.4');
339
+ await gitClient.beforeRelease();
340
+ await gitClient.stage('package.json');
341
+ await gitClient.commit({ message: 'Add this' });
342
+ await gitClient.tag();
343
+ try {
344
+ await gitClient.push();
345
+ } catch (e) {
346
+ // push would fail with an error since HEAD is behind origin
347
+ }
348
+ assert.equal(exec.mock.calls[15].arguments[0], 'git push origin --delete v1.2.4');
349
+ });
384
350
 
385
- {
386
- const options = { git: { getLatestTagFromAllRefs: true } };
351
+ test('should not touch existing history when rolling back', async t => {
352
+ childProcess.execSync('git init', execOpts);
353
+ const version = '1.2.3';
354
+ gitAdd(`{"version":"${version}"}`, 'package.json', 'Add package.json');
355
+ const options = { git: { requireCleanWorkingDir: true, commit: true, tag: true } };
387
356
  const gitClient = factory(Git, { options });
388
- gitAdd('main', 'file', 'Add file in main');
389
- const defaultBranchName = await gitClient.getBranchName();
390
- const developBranchName = 'develop';
391
- const featureBranchPrefix = 'feature';
392
- await gitClient.tag({ name: '1.0.0' });
393
- childProcess.execSync(`git branch ${developBranchName} ${defaultBranchName}`, execOpts);
394
- childProcess.execSync(`git checkout -b ${featureBranchPrefix}/first ${developBranchName}`, execOpts);
395
- gitAdd('feature/1', 'file', 'Update file in feature branch (1)');
396
- childProcess.execSync(`git checkout ${developBranchName}`, execOpts);
397
- childProcess.execSync(`git merge --no-ff ${featureBranchPrefix}/first`, execOpts);
398
- await gitClient.tag({ name: '1.1.0-rc.1' });
399
- childProcess.execSync(`git checkout ${defaultBranchName}`, execOpts);
400
- childProcess.execSync(`git merge --no-ff ${developBranchName}`, execOpts);
401
- await gitClient.tag({ name: '1.1.0' });
402
- childProcess.execSync(`git checkout -b ${featureBranchPrefix}/second ${developBranchName}`, execOpts);
403
- gitAdd('feature/2', 'file', 'Update file again, in feature branch (2)');
404
- childProcess.execSync(`git checkout ${developBranchName}`, execOpts);
405
- childProcess.execSync(`git merge --no-ff ${featureBranchPrefix}/second`, execOpts);
406
- t.is(await gitClient.getLatestTagName(), '1.1.0');
407
- }
408
-
409
- {
410
- const options = { git: { getLatestTagFromAllRefs: false } };
357
+ childProcess.execSync(`git tag ${version}`, execOpts);
358
+
359
+ const exec = t.mock.method(gitClient.shell, 'execFormattedCommand');
360
+ gitClient.config.setContext({ version: '1.2.4' });
361
+ await gitClient.beforeRelease();
362
+ await gitClient.commit();
363
+ await gitClient.rollbackOnce();
364
+
365
+ assert.equal(exec.mock.calls[3].arguments[0], 'git reset --hard HEAD');
366
+ });
367
+
368
+ test.skip('should not roll back with risky config', async () => {
369
+ childProcess.execSync('git init', execOpts);
370
+ const options = { git: { requireCleanWorkingDir: false, commit: true, tag: true } };
411
371
  const gitClient = factory(Git, { options });
412
- t.is(await gitClient.getLatestTagName(), '1.1.0-rc.1');
413
- }
372
+ await gitClient.beforeRelease();
373
+ assert.equal('rollbackOnce' in gitClient, false);
374
+ });
375
+
376
+ test('should return latest tag from default branch (not parent commit)', async () => {
377
+ childProcess.execSync('git init', execOpts);
378
+
379
+ {
380
+ const options = { git: { getLatestTagFromAllRefs: true } };
381
+ const gitClient = factory(Git, { options });
382
+ gitAdd('main', 'file', 'Add file in main');
383
+ const defaultBranchName = await gitClient.getBranchName();
384
+ const developBranchName = 'develop';
385
+ const featureBranchPrefix = 'feature';
386
+ await gitClient.tag({ name: '1.0.0' });
387
+ childProcess.execSync(`git branch ${developBranchName} ${defaultBranchName}`, execOpts);
388
+ childProcess.execSync(`git checkout -b ${featureBranchPrefix}/first ${developBranchName}`, execOpts);
389
+ gitAdd('feature/1', 'file', 'Update file in feature branch (1)');
390
+ childProcess.execSync(`git checkout ${developBranchName}`, execOpts);
391
+ childProcess.execSync(`git merge --no-ff ${featureBranchPrefix}/first`, execOpts);
392
+ await gitClient.tag({ name: '1.1.0-rc.1' });
393
+ childProcess.execSync(`git checkout ${defaultBranchName}`, execOpts);
394
+ childProcess.execSync(`git merge --no-ff ${developBranchName}`, execOpts);
395
+ await gitClient.tag({ name: '1.1.0' });
396
+ childProcess.execSync(`git checkout -b ${featureBranchPrefix}/second ${developBranchName}`, execOpts);
397
+ gitAdd('feature/2', 'file', 'Update file again, in feature branch (2)');
398
+ childProcess.execSync(`git checkout ${developBranchName}`, execOpts);
399
+ childProcess.execSync(`git merge --no-ff ${featureBranchPrefix}/second`, execOpts);
400
+ assert.equal(await gitClient.getLatestTagName(), '1.1.0');
401
+ }
402
+
403
+ {
404
+ const options = { git: { getLatestTagFromAllRefs: false } };
405
+ const gitClient = factory(Git, { options });
406
+ assert.equal(await gitClient.getLatestTagName(), '1.1.0-rc.1');
407
+ }
408
+ });
414
409
  });