Skip to content

Commit 565c2a5

Browse files
committed
Warn user if root package tag fallback is used
1 parent 8190f5f commit 565c2a5

File tree

4 files changed

+176
-98
lines changed

4 files changed

+176
-98
lines changed

src/fs.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ import {
55
} from '@metamask/action-utils';
66
import { wrapError, isErrorWithCode } from './misc-utils';
77

8+
/**
9+
* Represents a writeable stream, such as that represented by `process.stdout`
10+
* or `process.stderr`, or a fake one provided in tests.
11+
*/
12+
export type WriteStreamLike = Pick<fs.WriteStream, 'write'>;
13+
814
/**
915
* Reads the file at the given path, assuming its content is encoded as UTF-8.
1016
*

src/package.test.ts

Lines changed: 102 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ import path from 'path';
33
import { when } from 'jest-when';
44
import * as autoChangelog from '@metamask/auto-changelog';
55
import { SemVer } from 'semver';
6+
import { MockWritable } from 'stdio-mock';
67
import { withSandbox } from '../tests/helpers';
78
import {
89
buildMockPackage,
910
buildMockProject,
1011
buildMockManifest,
12+
createNoopWriteStream,
1113
} from '../tests/unit/helpers';
1214
import {
1315
readMonorepoRootPackage,
@@ -67,34 +69,31 @@ describe('package', () => {
6769
});
6870
});
6971

70-
it('throws if a tag matching the current version does not exist', async () => {
72+
it("flags the package as having been changed since its latest release if a tag matching the current version exists and changes have been made to the package's directory since the tag", async () => {
7173
jest
7274
.spyOn(packageManifestModule, 'readPackageManifest')
7375
.mockResolvedValue({
7476
unvalidated: {},
7577
validated: buildMockManifest({
76-
name: 'some-package',
7778
version: new SemVer('1.0.0'),
7879
}),
7980
});
8081
when(jest.spyOn(repoModule, 'hasChangesInDirectorySinceGitTag'))
8182
.calledWith('/path/to/project', '/path/to/package', 'v1.0.0')
8283
.mockResolvedValue(true);
8384

84-
const promiseForPkg = readMonorepoRootPackage({
85+
const pkg = await readMonorepoRootPackage({
8586
packageDirectoryPath: '/path/to/package',
8687
projectDirectoryPath: '/path/to/project',
87-
projectTagNames: ['some-tag'],
88+
projectTagNames: ['v1.0.0'],
8889
});
8990

90-
await expect(promiseForPkg).rejects.toThrow(
91-
new Error(
92-
'The package some-package has no Git tag for its current version 1.0.0 (expected "v1.0.0"), so this tool is unable to determine whether it should be included in this release. You will need to create a tag for this package in order to proceed.',
93-
),
94-
);
91+
expect(pkg).toMatchObject({
92+
hasChangesSinceLatestRelease: true,
93+
});
9594
});
9695

97-
it("flags the package as having been changed since its latest release if a tag matching the current version exists and changes have been made to the package's directory since the tag", async () => {
96+
it("does not flag the package as having been changed since its latest release if a tag matching the current version exists, but changes have not been made to the package's directory since the tag", async () => {
9897
jest
9998
.spyOn(packageManifestModule, 'readPackageManifest')
10099
.mockResolvedValue({
@@ -105,7 +104,7 @@ describe('package', () => {
105104
});
106105
when(jest.spyOn(repoModule, 'hasChangesInDirectorySinceGitTag'))
107106
.calledWith('/path/to/project', '/path/to/package', 'v1.0.0')
108-
.mockResolvedValue(true);
107+
.mockResolvedValue(false);
109108

110109
const pkg = await readMonorepoRootPackage({
111110
packageDirectoryPath: '/path/to/package',
@@ -114,11 +113,11 @@ describe('package', () => {
114113
});
115114

116115
expect(pkg).toMatchObject({
117-
hasChangesSinceLatestRelease: true,
116+
hasChangesSinceLatestRelease: false,
118117
});
119118
});
120119

121-
it("does not flag the package as having been changed since its latest release if a tag matching the current version exists, but changes have not been made to the package's directory since the tag", async () => {
120+
it('flags the package as having been changed since its latest release if a tag matching the current version does not exist', async () => {
122121
jest
123122
.spyOn(packageManifestModule, 'readPackageManifest')
124123
.mockResolvedValue({
@@ -127,45 +126,49 @@ describe('package', () => {
127126
version: new SemVer('1.0.0'),
128127
}),
129128
});
130-
when(jest.spyOn(repoModule, 'hasChangesInDirectorySinceGitTag'))
131-
.calledWith('/path/to/project', '/path/to/package', 'v1.0.0')
132-
.mockResolvedValue(false);
133129

134130
const pkg = await readMonorepoRootPackage({
135131
packageDirectoryPath: '/path/to/package',
136132
projectDirectoryPath: '/path/to/project',
137-
projectTagNames: ['v1.0.0'],
133+
projectTagNames: [],
138134
});
139135

140136
expect(pkg).toMatchObject({
141-
hasChangesSinceLatestRelease: false,
137+
hasChangesSinceLatestRelease: true,
142138
});
143139
});
144140

145-
it('flags the package as having been changed since its latest release if a tag matching the current version does not exist', async () => {
141+
it('throws if a tag matching the current version does not exist', async () => {
146142
jest
147143
.spyOn(packageManifestModule, 'readPackageManifest')
148144
.mockResolvedValue({
149145
unvalidated: {},
150146
validated: buildMockManifest({
147+
name: '@scope/workspace-package',
151148
version: new SemVer('1.0.0'),
152149
}),
153150
});
151+
when(jest.spyOn(repoModule, 'hasChangesInDirectorySinceGitTag'))
152+
.calledWith('/path/to/project', '/path/to/package', 'v1.0.0')
153+
.mockResolvedValue(true);
154154

155-
const pkg = await readMonorepoRootPackage({
155+
const promiseForPkg = readMonorepoRootPackage({
156156
packageDirectoryPath: '/path/to/package',
157157
projectDirectoryPath: '/path/to/project',
158-
projectTagNames: [],
158+
projectTagNames: ['some-tag'],
159159
});
160160

161-
expect(pkg).toMatchObject({
162-
hasChangesSinceLatestRelease: true,
163-
});
161+
await expect(promiseForPkg).rejects.toThrow(
162+
new Error(
163+
'The package @scope/workspace-package has no Git tag for its current version 1.0.0 (expected "v1.0.0"), so this tool is unable to determine whether it should be included in this release. You will need to create a tag for this package in order to proceed.',
164+
),
165+
);
164166
});
165167
});
166168

167169
describe('readMonorepoWorkspacePackage', () => {
168170
it('returns information about the file structure of the package located at the given directory', async () => {
171+
const stderr = createNoopWriteStream();
169172
jest
170173
.spyOn(packageManifestModule, 'readPackageManifest')
171174
.mockResolvedValue({
@@ -179,6 +182,7 @@ describe('package', () => {
179182
projectTagNames: [],
180183
rootPackageName: 'root-package',
181184
rootPackageVersion: new SemVer('5.0.0'),
185+
stderr,
182186
});
183187

184188
expect(pkg).toMatchObject({
@@ -191,6 +195,7 @@ describe('package', () => {
191195
it('returns information about the manifest (in both unvalidated and validated forms)', async () => {
192196
const unvalidatedManifest = {};
193197
const validatedManifest = buildMockManifest();
198+
const stderr = createNoopWriteStream();
194199
when(jest.spyOn(packageManifestModule, 'readPackageManifest'))
195200
.calledWith('/path/to/package/package.json')
196201
.mockResolvedValue({
@@ -204,6 +209,7 @@ describe('package', () => {
204209
projectTagNames: [],
205210
rootPackageName: 'root-package',
206211
rootPackageVersion: new SemVer('5.0.0'),
212+
stderr,
207213
});
208214

209215
expect(pkg).toMatchObject({
@@ -212,58 +218,32 @@ describe('package', () => {
212218
});
213219
});
214220

215-
it('throws if a tag matching the current version does not exist', async () => {
216-
const unvalidatedManifest = {};
217-
const validatedManifest = buildMockManifest({
218-
name: 'workspace-package',
219-
version: new SemVer('1.0.0'),
220-
});
221-
when(jest.spyOn(packageManifestModule, 'readPackageManifest'))
222-
.calledWith('/path/to/package/package.json')
223-
.mockResolvedValue({
224-
unvalidated: unvalidatedManifest,
225-
validated: validatedManifest,
226-
});
227-
228-
const promiseForPkg = readMonorepoWorkspacePackage({
229-
packageDirectoryPath: '/path/to/package',
230-
projectDirectoryPath: '/path/to/project',
231-
projectTagNames: ['some-tag'],
232-
rootPackageName: 'root-package',
233-
rootPackageVersion: new SemVer('5.0.0'),
234-
});
235-
236-
await expect(promiseForPkg).rejects.toThrow(
237-
new Error(
238-
'The workspace package workspace-package has no Git tag for its current version 1.0.0 (expected "[email protected]"), and the root package root-package has no Git tag for its current version 5.0.0 (expected "v5.0.0"), so this tool is unable to determine whether the workspace package should be included in this release. You will need to create tags for both of these packages in order to proceed.',
239-
),
240-
);
241-
});
242-
243221
it("flags the package as having been changed since its latest release if a tag matching the package name + version exists and changes have been made to the package's directory since the tag", async () => {
222+
const stderr = createNoopWriteStream();
244223
jest
245224
.spyOn(packageManifestModule, 'readPackageManifest')
246225
.mockResolvedValue({
247226
unvalidated: {},
248227
validated: buildMockManifest({
249-
name: '@scope/some-package',
228+
name: '@scope/workspace-package',
250229
version: new SemVer('1.0.0'),
251230
}),
252231
});
253232
when(jest.spyOn(repoModule, 'hasChangesInDirectorySinceGitTag'))
254233
.calledWith(
255234
'/path/to/project',
256235
'/path/to/package',
257-
'@scope/some[email protected]',
236+
'@scope/workspace[email protected]',
258237
)
259238
.mockResolvedValue(true);
260239

261240
const pkg = await readMonorepoWorkspacePackage({
262241
packageDirectoryPath: '/path/to/package',
263242
projectDirectoryPath: '/path/to/project',
264-
projectTagNames: ['@scope/some[email protected]'],
243+
projectTagNames: ['@scope/workspace[email protected]'],
265244
rootPackageName: 'root-package',
266245
rootPackageVersion: new SemVer('5.0.0'),
246+
stderr,
267247
});
268248

269249
expect(pkg).toMatchObject({
@@ -272,29 +252,31 @@ describe('package', () => {
272252
});
273253

274254
it("does not flag the package as having been changed since its latest release if a tag matching the package name + version exists, but changes have not been made to the package's directory since the tag", async () => {
255+
const stderr = createNoopWriteStream();
275256
jest
276257
.spyOn(packageManifestModule, 'readPackageManifest')
277258
.mockResolvedValue({
278259
unvalidated: {},
279260
validated: buildMockManifest({
280-
name: '@scope/some-package',
261+
name: '@scope/workspace-package',
281262
version: new SemVer('1.0.0'),
282263
}),
283264
});
284265
when(jest.spyOn(repoModule, 'hasChangesInDirectorySinceGitTag'))
285266
.calledWith(
286267
'/path/to/project',
287268
'/path/to/package',
288-
'@scope/some[email protected]',
269+
'@scope/workspace[email protected]',
289270
)
290271
.mockResolvedValue(false);
291272

292273
const pkg = await readMonorepoWorkspacePackage({
293274
packageDirectoryPath: '/path/to/package',
294275
projectDirectoryPath: '/path/to/project',
295-
projectTagNames: ['@scope/some[email protected]'],
276+
projectTagNames: ['@scope/workspace[email protected]'],
296277
rootPackageName: 'root-package',
297278
rootPackageVersion: new SemVer('5.0.0'),
279+
stderr,
298280
});
299281

300282
expect(pkg).toMatchObject({
@@ -303,11 +285,13 @@ describe('package', () => {
303285
});
304286

305287
it("flags the package as having been changed since its latest release if a tag matching 'v' + the root package version exists instead of the package name + version, and changes have been made to the package's directory since the tag", async () => {
288+
const stderr = createNoopWriteStream();
306289
jest
307290
.spyOn(packageManifestModule, 'readPackageManifest')
308291
.mockResolvedValue({
309292
unvalidated: {},
310293
validated: buildMockManifest({
294+
name: '@scope/workspace-package',
311295
version: new SemVer('1.0.0'),
312296
}),
313297
});
@@ -321,6 +305,7 @@ describe('package', () => {
321305
projectTagNames: ['v5.0.0'],
322306
rootPackageName: 'root-package',
323307
rootPackageVersion: new SemVer('5.0.0'),
308+
stderr,
324309
});
325310

326311
expect(pkg).toMatchObject({
@@ -329,6 +314,7 @@ describe('package', () => {
329314
});
330315

331316
it("does not flag the package as having been changed since its latest release if a tag matching 'v' + the root package version exists instead of the package name + version, but changes have not been made to the package's directory since the tag", async () => {
317+
const stderr = createNoopWriteStream();
332318
jest
333319
.spyOn(packageManifestModule, 'readPackageManifest')
334320
.mockResolvedValue({
@@ -347,14 +333,16 @@ describe('package', () => {
347333
projectTagNames: ['v5.0.0'],
348334
rootPackageName: 'root-package',
349335
rootPackageVersion: new SemVer('5.0.0'),
336+
stderr,
350337
});
351338

352339
expect(pkg).toMatchObject({
353340
hasChangesSinceLatestRelease: false,
354341
});
355342
});
356343

357-
it("flags the package as having been changed since its latest release if a tag matching neither the package name + version nor 'v' + the root package version exists", async () => {
344+
it('flags the package as having been changed since its latest release if the project has no tags', async () => {
345+
const stderr = createNoopWriteStream();
358346
jest
359347
.spyOn(packageManifestModule, 'readPackageManifest')
360348
.mockResolvedValue({
@@ -370,12 +358,67 @@ describe('package', () => {
370358
projectTagNames: [],
371359
rootPackageName: 'root-package',
372360
rootPackageVersion: new SemVer('5.0.0'),
361+
stderr,
373362
});
374363

375364
expect(pkg).toMatchObject({
376365
hasChangesSinceLatestRelease: true,
377366
});
378367
});
368+
369+
it("prints a warning if a tag matching 'v' + the root package version exists instead of the package name + version", async () => {
370+
const stderr = new MockWritable();
371+
when(jest.spyOn(packageManifestModule, 'readPackageManifest'))
372+
.calledWith('/path/to/package/package.json')
373+
.mockResolvedValue({
374+
unvalidated: {},
375+
validated: buildMockManifest({
376+
name: '@scope/workspace-package',
377+
version: new SemVer('1.0.0'),
378+
}),
379+
});
380+
381+
await readMonorepoWorkspacePackage({
382+
packageDirectoryPath: '/path/to/package',
383+
projectDirectoryPath: '/path/to/project',
384+
projectTagNames: ['v5.0.0'],
385+
rootPackageName: 'root-package',
386+
rootPackageVersion: new SemVer('5.0.0'),
387+
stderr,
388+
});
389+
390+
expect(stderr.data()).toStrictEqual([
391+
'WARNING: Could not determine changes for workspace package @scope/workspace-package version 1.0.0 based on Git tag "@scope/[email protected]"; using tag for root package root-package version 5.0.0, "v5.0.0", instead.\n',
392+
]);
393+
});
394+
395+
it("throws if the project has tags, but neither a tag matching the package name + version nor 'v' + the root package version exists", async () => {
396+
const stderr = createNoopWriteStream();
397+
when(jest.spyOn(packageManifestModule, 'readPackageManifest'))
398+
.calledWith('/path/to/package/package.json')
399+
.mockResolvedValue({
400+
unvalidated: {},
401+
validated: buildMockManifest({
402+
name: '@scope/workspace-package',
403+
version: new SemVer('1.0.0'),
404+
}),
405+
});
406+
407+
const promise = readMonorepoWorkspacePackage({
408+
packageDirectoryPath: '/path/to/package',
409+
projectDirectoryPath: '/path/to/project',
410+
projectTagNames: ['some-tag'],
411+
rootPackageName: 'root-package',
412+
rootPackageVersion: new SemVer('5.0.0'),
413+
stderr,
414+
});
415+
416+
await expect(promise).rejects.toThrow(
417+
new Error(
418+
'The current release of workspace package @scope/workspace-package, 1.0.0, has no corresponding Git tag "@scope/[email protected]", and the current release of root package root-package, 5.0.0, has no tag "v5.0.0". Hence, this tool is unable to know whether the workspace package changed and should be included in this release. You will need to create tags for both of these packages in order to proceed.',
419+
),
420+
);
421+
});
379422
});
380423

381424
describe('updatePackage', () => {

0 commit comments

Comments
 (0)