@capawesome/cli 2.1.4-dev.6aa4113.1756747594 → 2.1.4-dev.6aa4113.1756747595
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/dist/commands/mutate/version/get.js +35 -41
- package/dist/commands/mutate/version/get.test.js +85 -0
- package/dist/commands/mutate/version/hotfix.js +12 -13
- package/dist/commands/mutate/version/hotfix.test.js +49 -0
- package/dist/commands/mutate/version/major.js +5 -11
- package/dist/commands/mutate/version/major.test.js +49 -0
- package/dist/commands/mutate/version/minor.js +9 -10
- package/dist/commands/mutate/version/minor.test.js +48 -0
- package/dist/commands/mutate/version/patch.js +9 -10
- package/dist/commands/mutate/version/patch.test.js +48 -0
- package/dist/commands/mutate/version/set.js +7 -6
- package/dist/commands/mutate/version/set.test.js +41 -0
- package/dist/commands/mutate/version/sync.js +16 -22
- package/dist/commands/mutate/version/sync.test.js +90 -0
- package/dist/index.js +6 -3
- package/dist/services/mutate/version.js +5 -4
- package/dist/utils/error.js +10 -1
- package/dist/utils/error.test.js +36 -0
- package/package.json +1 -1
|
@@ -1,53 +1,47 @@
|
|
|
1
1
|
import versionService from '../../../services/mutate/version.js';
|
|
2
|
+
import { CliError } from '../../../utils/error.js';
|
|
2
3
|
import { versionToString } from '../../../utils/version.js';
|
|
3
4
|
import { defineCommand } from '@robingenz/zli';
|
|
4
5
|
import consola from 'consola';
|
|
5
6
|
export default defineCommand({
|
|
6
7
|
description: 'Get the version of the app from all relevant files',
|
|
7
8
|
action: async () => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
if (!allVersionsInSync || !hotfixInSync) {
|
|
31
|
-
consola.error('Versions are not synchronized across platforms:');
|
|
32
|
-
versions.forEach((pv) => {
|
|
33
|
-
const versionStr = versionToString(pv.version);
|
|
34
|
-
const hotfixStr = pv.platform !== 'web' && pv.version.hotfix ? ` (hotfix: ${pv.version.hotfix})` : '';
|
|
35
|
-
consola.log(` ${pv.platform}: ${versionStr}${hotfixStr} (${pv.source})`);
|
|
36
|
-
});
|
|
37
|
-
process.exit(1);
|
|
38
|
-
}
|
|
39
|
-
const versionStr = versionToString(firstVersion);
|
|
40
|
-
// Show hotfix if iOS or Android has one
|
|
41
|
-
const platformWithHotfix = versions.find((pv) => pv.platform !== 'web' && pv.version.hotfix && pv.version.hotfix > 0);
|
|
42
|
-
const hotfixStr = platformWithHotfix ? ` (hotfix: ${platformWithHotfix.version.hotfix})` : '';
|
|
43
|
-
consola.success(`Version: ${versionStr}${hotfixStr}`);
|
|
9
|
+
const versions = await versionService.getAllVersions();
|
|
10
|
+
if (versions.length === 0) {
|
|
11
|
+
throw new CliError('No platform versions found');
|
|
12
|
+
}
|
|
13
|
+
const firstVersion = versions[0].version;
|
|
14
|
+
// Check major.minor.patch synchronization for all platforms
|
|
15
|
+
const allVersionsInSync = versions.every((pv) => {
|
|
16
|
+
return (pv.version.major === firstVersion.major &&
|
|
17
|
+
pv.version.minor === firstVersion.minor &&
|
|
18
|
+
pv.version.patch === firstVersion.patch);
|
|
19
|
+
});
|
|
20
|
+
// Check hotfix synchronization between iOS and Android
|
|
21
|
+
const iosVersion = versions.find((pv) => pv.platform === 'ios');
|
|
22
|
+
const androidVersion = versions.find((pv) => pv.platform === 'android');
|
|
23
|
+
let hotfixInSync = true;
|
|
24
|
+
if (iosVersion && androidVersion) {
|
|
25
|
+
const iosHotfix = iosVersion.version.hotfix || 0;
|
|
26
|
+
const androidHotfix = androidVersion.version.hotfix || 0;
|
|
27
|
+
hotfixInSync = iosHotfix === androidHotfix;
|
|
28
|
+
}
|
|
29
|
+
if (!allVersionsInSync || !hotfixInSync) {
|
|
30
|
+
consola.error('Versions are not synchronized across platforms:');
|
|
44
31
|
versions.forEach((pv) => {
|
|
45
|
-
|
|
32
|
+
const versionStr = versionToString(pv.version);
|
|
33
|
+
const hotfixStr = pv.platform !== 'web' && pv.version.hotfix ? ` (hotfix: ${pv.version.hotfix})` : '';
|
|
34
|
+
consola.log(` ${pv.platform}: ${versionStr}${hotfixStr} (${pv.source})`);
|
|
46
35
|
});
|
|
36
|
+
throw new CliError('Versions are not synchronized across platforms');
|
|
47
37
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
38
|
+
const versionStr = versionToString(firstVersion);
|
|
39
|
+
// Show hotfix if iOS or Android has one
|
|
40
|
+
const platformWithHotfix = versions.find((pv) => pv.platform !== 'web' && pv.version.hotfix && pv.version.hotfix > 0);
|
|
41
|
+
const hotfixStr = platformWithHotfix ? ` (hotfix: ${platformWithHotfix.version.hotfix})` : '';
|
|
42
|
+
consola.success(`Version: ${versionStr}${hotfixStr}`);
|
|
43
|
+
versions.forEach((pv) => {
|
|
44
|
+
consola.log(` ${pv.platform}: ${pv.source}`);
|
|
45
|
+
});
|
|
52
46
|
},
|
|
53
47
|
});
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import versionService from '../../../services/mutate/version.js';
|
|
2
|
+
import { CliError } from '../../../utils/error.js';
|
|
3
|
+
import consola from 'consola';
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
+
import getCommand from './get.js';
|
|
6
|
+
vi.mock('consola');
|
|
7
|
+
vi.mock('@/services/mutate/version.js');
|
|
8
|
+
describe('mutate:version:get', () => {
|
|
9
|
+
const mockConsola = vi.mocked(consola);
|
|
10
|
+
const mockVersionService = vi.mocked(versionService);
|
|
11
|
+
const mockExit = vi.spyOn(process, 'exit').mockImplementation(() => undefined);
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
vi.clearAllMocks();
|
|
14
|
+
});
|
|
15
|
+
afterEach(() => {
|
|
16
|
+
vi.restoreAllMocks();
|
|
17
|
+
});
|
|
18
|
+
it('should display synchronized versions across all platforms', async () => {
|
|
19
|
+
const mockVersions = [
|
|
20
|
+
{
|
|
21
|
+
platform: 'ios',
|
|
22
|
+
version: { major: 1, minor: 2, patch: 3, hotfix: 0 },
|
|
23
|
+
source: 'ios/App/App.xcodeproj/project.pbxproj',
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
platform: 'android',
|
|
27
|
+
version: { major: 1, minor: 2, patch: 3, hotfix: 0 },
|
|
28
|
+
source: 'android/app/build.gradle',
|
|
29
|
+
},
|
|
30
|
+
{ platform: 'web', version: { major: 1, minor: 2, patch: 3 }, source: 'package.json' },
|
|
31
|
+
];
|
|
32
|
+
mockVersionService.getAllVersions.mockResolvedValue(mockVersions);
|
|
33
|
+
await getCommand.action({}, undefined);
|
|
34
|
+
expect(mockConsola.success).toHaveBeenCalledWith('Version: 1.2.3');
|
|
35
|
+
expect(mockConsola.log).toHaveBeenCalledWith(' ios: ios/App/App.xcodeproj/project.pbxproj');
|
|
36
|
+
expect(mockConsola.log).toHaveBeenCalledWith(' android: android/app/build.gradle');
|
|
37
|
+
expect(mockConsola.log).toHaveBeenCalledWith(' web: package.json');
|
|
38
|
+
expect(mockExit).not.toHaveBeenCalled();
|
|
39
|
+
});
|
|
40
|
+
it('should display hotfix when iOS/Android have one', async () => {
|
|
41
|
+
const mockVersions = [
|
|
42
|
+
{
|
|
43
|
+
platform: 'ios',
|
|
44
|
+
version: { major: 1, minor: 2, patch: 3, hotfix: 5 },
|
|
45
|
+
source: 'ios/App/App.xcodeproj/project.pbxproj',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
platform: 'android',
|
|
49
|
+
version: { major: 1, minor: 2, patch: 3, hotfix: 5 },
|
|
50
|
+
source: 'android/app/build.gradle',
|
|
51
|
+
},
|
|
52
|
+
{ platform: 'web', version: { major: 1, minor: 2, patch: 3 }, source: 'package.json' },
|
|
53
|
+
];
|
|
54
|
+
mockVersionService.getAllVersions.mockResolvedValue(mockVersions);
|
|
55
|
+
await getCommand.action({}, undefined);
|
|
56
|
+
expect(mockConsola.success).toHaveBeenCalledWith('Version: 1.2.3 (hotfix: 5)');
|
|
57
|
+
});
|
|
58
|
+
it('should error when versions are not synchronized', async () => {
|
|
59
|
+
const mockVersions = [
|
|
60
|
+
{
|
|
61
|
+
platform: 'ios',
|
|
62
|
+
version: { major: 1, minor: 2, patch: 3, hotfix: 0 },
|
|
63
|
+
source: 'ios/App/App.xcodeproj/project.pbxproj',
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
platform: 'android',
|
|
67
|
+
version: { major: 1, minor: 2, patch: 4, hotfix: 0 },
|
|
68
|
+
source: 'android/app/build.gradle',
|
|
69
|
+
},
|
|
70
|
+
{ platform: 'web', version: { major: 1, minor: 2, patch: 3 }, source: 'package.json' },
|
|
71
|
+
];
|
|
72
|
+
mockVersionService.getAllVersions.mockResolvedValue(mockVersions);
|
|
73
|
+
await expect(getCommand.action({}, undefined)).rejects.toThrow(CliError);
|
|
74
|
+
await expect(getCommand.action({}, undefined)).rejects.toThrow('Versions are not synchronized across platforms');
|
|
75
|
+
expect(mockConsola.error).toHaveBeenCalledWith('Versions are not synchronized across platforms:');
|
|
76
|
+
expect(mockConsola.log).toHaveBeenCalledWith(' ios: 1.2.3 (ios/App/App.xcodeproj/project.pbxproj)');
|
|
77
|
+
expect(mockConsola.log).toHaveBeenCalledWith(' android: 1.2.4 (android/app/build.gradle)');
|
|
78
|
+
expect(mockConsola.log).toHaveBeenCalledWith(' web: 1.2.3 (package.json)');
|
|
79
|
+
});
|
|
80
|
+
it('should error when no platform versions found', async () => {
|
|
81
|
+
mockVersionService.getAllVersions.mockResolvedValue([]);
|
|
82
|
+
await expect(getCommand.action({}, undefined)).rejects.toThrow(CliError);
|
|
83
|
+
await expect(getCommand.action({}, undefined)).rejects.toThrow('No platform versions found');
|
|
84
|
+
});
|
|
85
|
+
});
|
|
@@ -1,23 +1,22 @@
|
|
|
1
1
|
import versionService from '../../../services/mutate/version.js';
|
|
2
|
+
import { CliError } from '../../../utils/error.js';
|
|
2
3
|
import { incrementHotfix, versionToString } from '../../../utils/version.js';
|
|
3
4
|
import { defineCommand } from '@robingenz/zli';
|
|
4
5
|
import consola from 'consola';
|
|
5
6
|
export default defineCommand({
|
|
6
7
|
description: 'Increment the hotfix version of the app in all relevant files',
|
|
7
8
|
action: async () => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const newHotfix = newVersion.hotfix || 0;
|
|
14
|
-
consola.info(`Incrementing hotfix for version ${versionStr} (${currentHotfix} -> ${newHotfix})...`);
|
|
15
|
-
await versionService.setVersion(newVersion);
|
|
16
|
-
consola.success(`Hotfix incremented for version ${versionStr} (now ${newHotfix})`);
|
|
17
|
-
}
|
|
18
|
-
catch (error) {
|
|
19
|
-
consola.error(error instanceof Error ? error.message : String(error));
|
|
20
|
-
process.exit(1);
|
|
9
|
+
const currentVersion = await versionService.ensureVersionsInSync();
|
|
10
|
+
// Check for hotfix version limit
|
|
11
|
+
const currentHotfix = currentVersion.hotfix || 0;
|
|
12
|
+
if (currentHotfix >= 99) {
|
|
13
|
+
throw new CliError('Cannot increment hotfix version: would exceed maximum value of 99');
|
|
21
14
|
}
|
|
15
|
+
const newVersion = incrementHotfix(currentVersion);
|
|
16
|
+
const versionStr = versionToString(currentVersion);
|
|
17
|
+
const newHotfix = newVersion.hotfix || 0;
|
|
18
|
+
consola.info(`Incrementing hotfix for version ${versionStr} (${currentHotfix} -> ${newHotfix})...`);
|
|
19
|
+
await versionService.setVersion(newVersion);
|
|
20
|
+
consola.success(`Hotfix incremented for version ${versionStr} (now ${newHotfix})`);
|
|
22
21
|
},
|
|
23
22
|
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import versionService from '../../../services/mutate/version.js';
|
|
2
|
+
import { CliError } from '../../../utils/error.js';
|
|
3
|
+
import consola from 'consola';
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
+
import hotfixCommand from './hotfix.js';
|
|
6
|
+
vi.mock('consola');
|
|
7
|
+
vi.mock('@/services/mutate/version.js');
|
|
8
|
+
describe('mutate:version:hotfix', () => {
|
|
9
|
+
const mockConsola = vi.mocked(consola);
|
|
10
|
+
const mockVersionService = vi.mocked(versionService);
|
|
11
|
+
const mockExit = vi.spyOn(process, 'exit').mockImplementation(() => undefined);
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
vi.clearAllMocks();
|
|
14
|
+
});
|
|
15
|
+
afterEach(() => {
|
|
16
|
+
vi.restoreAllMocks();
|
|
17
|
+
});
|
|
18
|
+
it('should increment hotfix version from 0', async () => {
|
|
19
|
+
const currentVersion = { major: 1, minor: 2, patch: 3, hotfix: 0 };
|
|
20
|
+
mockVersionService.ensureVersionsInSync.mockResolvedValue(currentVersion);
|
|
21
|
+
mockVersionService.setVersion.mockResolvedValue(undefined);
|
|
22
|
+
await hotfixCommand.action({}, undefined);
|
|
23
|
+
expect(mockConsola.info).toHaveBeenCalledWith('Incrementing hotfix for version 1.2.3 (0 -> 1)...');
|
|
24
|
+
expect(mockVersionService.setVersion).toHaveBeenCalledWith({ major: 1, minor: 2, patch: 3, hotfix: 1 });
|
|
25
|
+
expect(mockConsola.success).toHaveBeenCalledWith('Hotfix incremented for version 1.2.3 (now 1)');
|
|
26
|
+
expect(mockExit).not.toHaveBeenCalled();
|
|
27
|
+
});
|
|
28
|
+
it('should increment existing hotfix version', async () => {
|
|
29
|
+
const currentVersion = { major: 1, minor: 2, patch: 3, hotfix: 5 };
|
|
30
|
+
mockVersionService.ensureVersionsInSync.mockResolvedValue(currentVersion);
|
|
31
|
+
mockVersionService.setVersion.mockResolvedValue(undefined);
|
|
32
|
+
await hotfixCommand.action({}, undefined);
|
|
33
|
+
expect(mockConsola.info).toHaveBeenCalledWith('Incrementing hotfix for version 1.2.3 (5 -> 6)...');
|
|
34
|
+
expect(mockVersionService.setVersion).toHaveBeenCalledWith({ major: 1, minor: 2, patch: 3, hotfix: 6 });
|
|
35
|
+
expect(mockConsola.success).toHaveBeenCalledWith('Hotfix incremented for version 1.2.3 (now 6)');
|
|
36
|
+
});
|
|
37
|
+
it('should handle maximum hotfix version limit', async () => {
|
|
38
|
+
const currentVersion = { major: 1, minor: 2, patch: 3, hotfix: 99 };
|
|
39
|
+
mockVersionService.ensureVersionsInSync.mockResolvedValue(currentVersion);
|
|
40
|
+
await expect(hotfixCommand.action({}, undefined)).rejects.toThrow(CliError);
|
|
41
|
+
await expect(hotfixCommand.action({}, undefined)).rejects.toThrow('Cannot increment hotfix version: would exceed maximum value of 99');
|
|
42
|
+
expect(mockVersionService.setVersion).not.toHaveBeenCalled();
|
|
43
|
+
});
|
|
44
|
+
it('should handle hotfix sync errors between iOS and Android', async () => {
|
|
45
|
+
mockVersionService.ensureVersionsInSync.mockRejectedValue(new CliError('Hotfix versions are not synchronized between iOS and Android'));
|
|
46
|
+
await expect(hotfixCommand.action({}, undefined)).rejects.toThrow('Hotfix versions are not synchronized between iOS and Android');
|
|
47
|
+
expect(mockVersionService.setVersion).not.toHaveBeenCalled();
|
|
48
|
+
});
|
|
49
|
+
});
|
|
@@ -5,16 +5,10 @@ import consola from 'consola';
|
|
|
5
5
|
export default defineCommand({
|
|
6
6
|
description: 'Increment the major version of the app in all relevant files',
|
|
7
7
|
action: async () => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
consola.success(`Major version incremented to ${versionToString(newVersion)}`);
|
|
14
|
-
}
|
|
15
|
-
catch (error) {
|
|
16
|
-
consola.error(error instanceof Error ? error.message : String(error));
|
|
17
|
-
process.exit(1);
|
|
18
|
-
}
|
|
8
|
+
const currentVersion = await versionService.ensureVersionsInSync();
|
|
9
|
+
const newVersion = incrementMajor(currentVersion);
|
|
10
|
+
consola.info(`Incrementing major version from ${versionToString(currentVersion)} to ${versionToString(newVersion)}...`);
|
|
11
|
+
await versionService.setVersion(newVersion);
|
|
12
|
+
consola.success(`Major version incremented to ${versionToString(newVersion)}`);
|
|
19
13
|
},
|
|
20
14
|
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import versionService from '../../../services/mutate/version.js';
|
|
2
|
+
import { CliError } from '../../../utils/error.js';
|
|
3
|
+
import consola from 'consola';
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
+
import majorCommand from './major.js';
|
|
6
|
+
vi.mock('consola');
|
|
7
|
+
vi.mock('@/services/mutate/version.js');
|
|
8
|
+
describe('mutate:version:major', () => {
|
|
9
|
+
const mockConsola = vi.mocked(consola);
|
|
10
|
+
const mockVersionService = vi.mocked(versionService);
|
|
11
|
+
const mockExit = vi.spyOn(process, 'exit').mockImplementation(() => undefined);
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
vi.clearAllMocks();
|
|
14
|
+
});
|
|
15
|
+
afterEach(() => {
|
|
16
|
+
vi.restoreAllMocks();
|
|
17
|
+
});
|
|
18
|
+
it('should increment major version successfully', async () => {
|
|
19
|
+
const currentVersion = { major: 1, minor: 2, patch: 3, hotfix: 0 };
|
|
20
|
+
mockVersionService.ensureVersionsInSync.mockResolvedValue(currentVersion);
|
|
21
|
+
mockVersionService.setVersion.mockResolvedValue(undefined);
|
|
22
|
+
await majorCommand.action({}, undefined);
|
|
23
|
+
expect(mockConsola.info).toHaveBeenCalledWith('Incrementing major version from 1.2.3 to 2.0.0...');
|
|
24
|
+
expect(mockVersionService.setVersion).toHaveBeenCalledWith({ major: 2, minor: 0, patch: 0 });
|
|
25
|
+
expect(mockConsola.success).toHaveBeenCalledWith('Major version incremented to 2.0.0');
|
|
26
|
+
expect(mockExit).not.toHaveBeenCalled();
|
|
27
|
+
});
|
|
28
|
+
it('should handle large major versions', async () => {
|
|
29
|
+
const currentVersion = { major: 999, minor: 2, patch: 3, hotfix: 0 };
|
|
30
|
+
mockVersionService.ensureVersionsInSync.mockResolvedValue(currentVersion);
|
|
31
|
+
mockVersionService.setVersion.mockResolvedValue(undefined);
|
|
32
|
+
await majorCommand.action({}, undefined);
|
|
33
|
+
expect(mockConsola.info).toHaveBeenCalledWith('Incrementing major version from 999.2.3 to 1000.0.0...');
|
|
34
|
+
expect(mockVersionService.setVersion).toHaveBeenCalledWith({ major: 1000, minor: 0, patch: 0 });
|
|
35
|
+
expect(mockConsola.success).toHaveBeenCalledWith('Major version incremented to 1000.0.0');
|
|
36
|
+
});
|
|
37
|
+
it('should handle version sync errors', async () => {
|
|
38
|
+
mockVersionService.ensureVersionsInSync.mockRejectedValue(new CliError('Versions are not synchronized across platforms'));
|
|
39
|
+
await expect(majorCommand.action({}, undefined)).rejects.toThrow('Versions are not synchronized across platforms');
|
|
40
|
+
expect(mockVersionService.setVersion).not.toHaveBeenCalled();
|
|
41
|
+
});
|
|
42
|
+
it('should handle service errors during set', async () => {
|
|
43
|
+
const currentVersion = { major: 1, minor: 2, patch: 3, hotfix: 0 };
|
|
44
|
+
mockVersionService.ensureVersionsInSync.mockResolvedValue(currentVersion);
|
|
45
|
+
mockVersionService.setVersion.mockRejectedValue(new Error('Failed to update version'));
|
|
46
|
+
await expect(majorCommand.action({}, undefined)).rejects.toThrow('Failed to update version');
|
|
47
|
+
expect(mockVersionService.setVersion).toHaveBeenCalledWith({ major: 2, minor: 0, patch: 0 });
|
|
48
|
+
});
|
|
49
|
+
});
|
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
import versionService from '../../../services/mutate/version.js';
|
|
2
|
+
import { CliError } from '../../../utils/error.js';
|
|
2
3
|
import { incrementMinor, versionToString } from '../../../utils/version.js';
|
|
3
4
|
import { defineCommand } from '@robingenz/zli';
|
|
4
5
|
import consola from 'consola';
|
|
5
6
|
export default defineCommand({
|
|
6
7
|
description: 'Increment the minor version of the app in all relevant files',
|
|
7
8
|
action: async () => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
await versionService.setVersion(newVersion);
|
|
13
|
-
consola.success(`Minor version incremented to ${versionToString(newVersion)}`);
|
|
14
|
-
}
|
|
15
|
-
catch (error) {
|
|
16
|
-
consola.error(error instanceof Error ? error.message : String(error));
|
|
17
|
-
process.exit(1);
|
|
9
|
+
const currentVersion = await versionService.ensureVersionsInSync();
|
|
10
|
+
// Check for minor version limit
|
|
11
|
+
if (currentVersion.minor >= 999) {
|
|
12
|
+
throw new CliError('Cannot increment minor version: would exceed maximum value of 999');
|
|
18
13
|
}
|
|
14
|
+
const newVersion = incrementMinor(currentVersion);
|
|
15
|
+
consola.info(`Incrementing minor version from ${versionToString(currentVersion)} to ${versionToString(newVersion)}...`);
|
|
16
|
+
await versionService.setVersion(newVersion);
|
|
17
|
+
consola.success(`Minor version incremented to ${versionToString(newVersion)}`);
|
|
19
18
|
},
|
|
20
19
|
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import versionService from '../../../services/mutate/version.js';
|
|
2
|
+
import { CliError } from '../../../utils/error.js';
|
|
3
|
+
import consola from 'consola';
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
+
import minorCommand from './minor.js';
|
|
6
|
+
vi.mock('consola');
|
|
7
|
+
vi.mock('@/services/mutate/version.js');
|
|
8
|
+
describe('mutate:version:minor', () => {
|
|
9
|
+
const mockConsola = vi.mocked(consola);
|
|
10
|
+
const mockVersionService = vi.mocked(versionService);
|
|
11
|
+
const mockExit = vi.spyOn(process, 'exit').mockImplementation(() => undefined);
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
vi.clearAllMocks();
|
|
14
|
+
});
|
|
15
|
+
afterEach(() => {
|
|
16
|
+
vi.restoreAllMocks();
|
|
17
|
+
});
|
|
18
|
+
it('should increment minor version successfully', async () => {
|
|
19
|
+
const currentVersion = { major: 1, minor: 2, patch: 3, hotfix: 0 };
|
|
20
|
+
mockVersionService.ensureVersionsInSync.mockResolvedValue(currentVersion);
|
|
21
|
+
mockVersionService.setVersion.mockResolvedValue(undefined);
|
|
22
|
+
await minorCommand.action({}, undefined);
|
|
23
|
+
expect(mockConsola.info).toHaveBeenCalledWith('Incrementing minor version from 1.2.3 to 1.3.0...');
|
|
24
|
+
expect(mockVersionService.setVersion).toHaveBeenCalledWith({ major: 1, minor: 3, patch: 0 });
|
|
25
|
+
expect(mockConsola.success).toHaveBeenCalledWith('Minor version incremented to 1.3.0');
|
|
26
|
+
expect(mockExit).not.toHaveBeenCalled();
|
|
27
|
+
});
|
|
28
|
+
it('should handle maximum minor version limit', async () => {
|
|
29
|
+
const currentVersion = { major: 1, minor: 999, patch: 3, hotfix: 0 };
|
|
30
|
+
mockVersionService.ensureVersionsInSync.mockResolvedValue(currentVersion);
|
|
31
|
+
await expect(minorCommand.action({}, undefined)).rejects.toThrow(CliError);
|
|
32
|
+
await expect(minorCommand.action({}, undefined)).rejects.toThrow('Cannot increment minor version: would exceed maximum value of 999');
|
|
33
|
+
expect(mockVersionService.setVersion).not.toHaveBeenCalled();
|
|
34
|
+
});
|
|
35
|
+
it('should reset patch and hotfix when incrementing minor', async () => {
|
|
36
|
+
const currentVersion = { major: 1, minor: 2, patch: 5, hotfix: 3 };
|
|
37
|
+
mockVersionService.ensureVersionsInSync.mockResolvedValue(currentVersion);
|
|
38
|
+
mockVersionService.setVersion.mockResolvedValue(undefined);
|
|
39
|
+
await minorCommand.action({}, undefined);
|
|
40
|
+
expect(mockVersionService.setVersion).toHaveBeenCalledWith({ major: 1, minor: 3, patch: 0 });
|
|
41
|
+
expect(mockConsola.success).toHaveBeenCalledWith('Minor version incremented to 1.3.0');
|
|
42
|
+
});
|
|
43
|
+
it('should handle version sync errors', async () => {
|
|
44
|
+
mockVersionService.ensureVersionsInSync.mockRejectedValue(new CliError('Versions are not synchronized across platforms'));
|
|
45
|
+
await expect(minorCommand.action({}, undefined)).rejects.toThrow('Versions are not synchronized across platforms');
|
|
46
|
+
expect(mockVersionService.setVersion).not.toHaveBeenCalled();
|
|
47
|
+
});
|
|
48
|
+
});
|
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
import versionService from '../../../services/mutate/version.js';
|
|
2
|
+
import { CliError } from '../../../utils/error.js';
|
|
2
3
|
import { incrementPatch, versionToString } from '../../../utils/version.js';
|
|
3
4
|
import { defineCommand } from '@robingenz/zli';
|
|
4
5
|
import consola from 'consola';
|
|
5
6
|
export default defineCommand({
|
|
6
7
|
description: 'Increment the patch version of the app in all relevant files',
|
|
7
8
|
action: async () => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
await versionService.setVersion(newVersion);
|
|
13
|
-
consola.success(`Patch version incremented to ${versionToString(newVersion)}`);
|
|
14
|
-
}
|
|
15
|
-
catch (error) {
|
|
16
|
-
consola.error(error instanceof Error ? error.message : String(error));
|
|
17
|
-
process.exit(1);
|
|
9
|
+
const currentVersion = await versionService.ensureVersionsInSync();
|
|
10
|
+
// Check for patch version limit
|
|
11
|
+
if (currentVersion.patch >= 99) {
|
|
12
|
+
throw new CliError('Cannot increment patch version: would exceed maximum value of 99');
|
|
18
13
|
}
|
|
14
|
+
const newVersion = incrementPatch(currentVersion);
|
|
15
|
+
consola.info(`Incrementing patch version from ${versionToString(currentVersion)} to ${versionToString(newVersion)}...`);
|
|
16
|
+
await versionService.setVersion(newVersion);
|
|
17
|
+
consola.success(`Patch version incremented to ${versionToString(newVersion)}`);
|
|
19
18
|
},
|
|
20
19
|
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import versionService from '../../../services/mutate/version.js';
|
|
2
|
+
import { CliError } from '../../../utils/error.js';
|
|
3
|
+
import consola from 'consola';
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
+
import patchCommand from './patch.js';
|
|
6
|
+
vi.mock('consola');
|
|
7
|
+
vi.mock('@/services/mutate/version.js');
|
|
8
|
+
describe('mutate:version:patch', () => {
|
|
9
|
+
const mockConsola = vi.mocked(consola);
|
|
10
|
+
const mockVersionService = vi.mocked(versionService);
|
|
11
|
+
const mockExit = vi.spyOn(process, 'exit').mockImplementation(() => undefined);
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
vi.clearAllMocks();
|
|
14
|
+
});
|
|
15
|
+
afterEach(() => {
|
|
16
|
+
vi.restoreAllMocks();
|
|
17
|
+
});
|
|
18
|
+
it('should increment patch version successfully', async () => {
|
|
19
|
+
const currentVersion = { major: 1, minor: 2, patch: 3, hotfix: 0 };
|
|
20
|
+
mockVersionService.ensureVersionsInSync.mockResolvedValue(currentVersion);
|
|
21
|
+
mockVersionService.setVersion.mockResolvedValue(undefined);
|
|
22
|
+
await patchCommand.action({}, undefined);
|
|
23
|
+
expect(mockConsola.info).toHaveBeenCalledWith('Incrementing patch version from 1.2.3 to 1.2.4...');
|
|
24
|
+
expect(mockVersionService.setVersion).toHaveBeenCalledWith({ major: 1, minor: 2, patch: 4 });
|
|
25
|
+
expect(mockConsola.success).toHaveBeenCalledWith('Patch version incremented to 1.2.4');
|
|
26
|
+
expect(mockExit).not.toHaveBeenCalled();
|
|
27
|
+
});
|
|
28
|
+
it('should handle maximum patch version limit', async () => {
|
|
29
|
+
const currentVersion = { major: 1, minor: 2, patch: 99, hotfix: 0 };
|
|
30
|
+
mockVersionService.ensureVersionsInSync.mockResolvedValue(currentVersion);
|
|
31
|
+
await expect(patchCommand.action({}, undefined)).rejects.toThrow(CliError);
|
|
32
|
+
await expect(patchCommand.action({}, undefined)).rejects.toThrow('Cannot increment patch version: would exceed maximum value of 99');
|
|
33
|
+
expect(mockVersionService.setVersion).not.toHaveBeenCalled();
|
|
34
|
+
});
|
|
35
|
+
it('should reset hotfix when incrementing patch', async () => {
|
|
36
|
+
const currentVersion = { major: 1, minor: 2, patch: 3, hotfix: 5 };
|
|
37
|
+
mockVersionService.ensureVersionsInSync.mockResolvedValue(currentVersion);
|
|
38
|
+
mockVersionService.setVersion.mockResolvedValue(undefined);
|
|
39
|
+
await patchCommand.action({}, undefined);
|
|
40
|
+
expect(mockVersionService.setVersion).toHaveBeenCalledWith({ major: 1, minor: 2, patch: 4 });
|
|
41
|
+
expect(mockConsola.success).toHaveBeenCalledWith('Patch version incremented to 1.2.4');
|
|
42
|
+
});
|
|
43
|
+
it('should handle version sync errors', async () => {
|
|
44
|
+
mockVersionService.ensureVersionsInSync.mockRejectedValue(new CliError('Versions are not synchronized across platforms'));
|
|
45
|
+
await expect(patchCommand.action({}, undefined)).rejects.toThrow('Versions are not synchronized across platforms');
|
|
46
|
+
expect(mockVersionService.setVersion).not.toHaveBeenCalled();
|
|
47
|
+
});
|
|
48
|
+
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import versionService from '../../../services/mutate/version.js';
|
|
2
|
+
import { CliError } from '../../../utils/error.js';
|
|
2
3
|
import { parseVersion, versionToString } from '../../../utils/version.js';
|
|
3
4
|
import { defineCommand } from '@robingenz/zli';
|
|
4
5
|
import consola from 'consola';
|
|
@@ -7,15 +8,15 @@ export default defineCommand({
|
|
|
7
8
|
description: 'Set the version of the app in all relevant files',
|
|
8
9
|
args: z.tuple([z.string().describe('Version')]),
|
|
9
10
|
action: async (_options, args) => {
|
|
11
|
+
let version;
|
|
10
12
|
try {
|
|
11
|
-
|
|
12
|
-
consola.info(`Setting version to ${versionToString(version)}...`);
|
|
13
|
-
await versionService.setVersion(version);
|
|
14
|
-
consola.success(`Version set to ${versionToString(version)}`);
|
|
13
|
+
version = parseVersion(args[0]);
|
|
15
14
|
}
|
|
16
15
|
catch (error) {
|
|
17
|
-
|
|
18
|
-
process.exit(1);
|
|
16
|
+
throw new CliError("Invalid version format. Please use the format 'major.minor.patch' (e.g. '1.2.3').");
|
|
19
17
|
}
|
|
18
|
+
consola.info(`Setting version to ${versionToString(version)}...`);
|
|
19
|
+
await versionService.setVersion(version);
|
|
20
|
+
consola.success(`Version set to ${versionToString(version)}`);
|
|
20
21
|
},
|
|
21
22
|
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import versionService from '../../../services/mutate/version.js';
|
|
2
|
+
import { CliError } from '../../../utils/error.js';
|
|
3
|
+
import consola from 'consola';
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
+
import setCommand from './set.js';
|
|
6
|
+
vi.mock('consola');
|
|
7
|
+
vi.mock('@/services/mutate/version.js');
|
|
8
|
+
describe('mutate:version:set', () => {
|
|
9
|
+
const mockConsola = vi.mocked(consola);
|
|
10
|
+
const mockVersionService = vi.mocked(versionService);
|
|
11
|
+
const mockExit = vi.spyOn(process, 'exit').mockImplementation(() => undefined);
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
vi.clearAllMocks();
|
|
14
|
+
});
|
|
15
|
+
afterEach(() => {
|
|
16
|
+
vi.restoreAllMocks();
|
|
17
|
+
});
|
|
18
|
+
it('should set a valid version', async () => {
|
|
19
|
+
mockVersionService.setVersion.mockResolvedValue(undefined);
|
|
20
|
+
await setCommand.action({}, ['1.2.3']);
|
|
21
|
+
expect(mockConsola.info).toHaveBeenCalledWith('Setting version to 1.2.3...');
|
|
22
|
+
expect(mockVersionService.setVersion).toHaveBeenCalledWith({ major: 1, minor: 2, patch: 3 });
|
|
23
|
+
expect(mockConsola.success).toHaveBeenCalledWith('Version set to 1.2.3');
|
|
24
|
+
expect(mockExit).not.toHaveBeenCalled();
|
|
25
|
+
});
|
|
26
|
+
it('should handle invalid version format', async () => {
|
|
27
|
+
await expect(setCommand.action({}, ['1.2'])).rejects.toThrow(CliError);
|
|
28
|
+
await expect(setCommand.action({}, ['1.2'])).rejects.toThrow("Invalid version format. Please use the format 'major.minor.patch' (e.g. '1.2.3').");
|
|
29
|
+
expect(mockVersionService.setVersion).not.toHaveBeenCalled();
|
|
30
|
+
});
|
|
31
|
+
it('should handle non-numeric version parts', async () => {
|
|
32
|
+
await expect(setCommand.action({}, ['1.2.abc'])).rejects.toThrow(CliError);
|
|
33
|
+
await expect(setCommand.action({}, ['1.2.abc'])).rejects.toThrow("Invalid version format. Please use the format 'major.minor.patch' (e.g. '1.2.3').");
|
|
34
|
+
expect(mockVersionService.setVersion).not.toHaveBeenCalled();
|
|
35
|
+
});
|
|
36
|
+
it('should handle service errors', async () => {
|
|
37
|
+
mockVersionService.setVersion.mockRejectedValue(new Error('Failed to set version'));
|
|
38
|
+
await expect(setCommand.action({}, ['1.2.3'])).rejects.toThrow('Failed to set version');
|
|
39
|
+
expect(mockVersionService.setVersion).toHaveBeenCalledWith({ major: 1, minor: 2, patch: 3 });
|
|
40
|
+
});
|
|
41
|
+
});
|
|
@@ -1,32 +1,26 @@
|
|
|
1
1
|
import versionService from '../../../services/mutate/version.js';
|
|
2
|
+
import { CliError } from '../../../utils/error.js';
|
|
2
3
|
import { versionToString } from '../../../utils/version.js';
|
|
3
4
|
import { defineCommand } from '@robingenz/zli';
|
|
4
5
|
import consola from 'consola';
|
|
5
6
|
export default defineCommand({
|
|
6
7
|
description: 'Set the highest version number among all platforms in all relevant files',
|
|
7
8
|
action: async () => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
consola.error('No platform versions found');
|
|
12
|
-
process.exit(1);
|
|
13
|
-
}
|
|
14
|
-
const highestVersion = await versionService.getHighestVersion();
|
|
15
|
-
consola.info('Current versions:');
|
|
16
|
-
versions.forEach((pv) => {
|
|
17
|
-
const versionStr = versionToString(pv.version);
|
|
18
|
-
const hotfixStr = pv.platform !== 'web' && pv.version.hotfix ? ` (hotfix: ${pv.version.hotfix})` : '';
|
|
19
|
-
consola.log(` ${pv.platform}: ${versionStr}${hotfixStr}`);
|
|
20
|
-
});
|
|
21
|
-
const highestVersionStr = versionToString(highestVersion);
|
|
22
|
-
const hotfixStr = highestVersion.hotfix ? ` (hotfix: ${highestVersion.hotfix})` : '';
|
|
23
|
-
consola.info(`Syncing all platforms to highest version: ${highestVersionStr}${hotfixStr}...`);
|
|
24
|
-
await versionService.setVersion(highestVersion);
|
|
25
|
-
consola.success(`All platforms synced to version ${highestVersionStr}${hotfixStr}`);
|
|
26
|
-
}
|
|
27
|
-
catch (error) {
|
|
28
|
-
consola.error(error instanceof Error ? error.message : String(error));
|
|
29
|
-
process.exit(1);
|
|
9
|
+
const versions = await versionService.getAllVersions();
|
|
10
|
+
if (versions.length === 0) {
|
|
11
|
+
throw new CliError('No platform versions found');
|
|
30
12
|
}
|
|
13
|
+
const highestVersion = await versionService.getHighestVersion();
|
|
14
|
+
consola.info('Current versions:');
|
|
15
|
+
versions.forEach((pv) => {
|
|
16
|
+
const versionStr = versionToString(pv.version);
|
|
17
|
+
const hotfixStr = pv.platform !== 'web' && pv.version.hotfix ? ` (hotfix: ${pv.version.hotfix})` : '';
|
|
18
|
+
consola.log(` ${pv.platform}: ${versionStr}${hotfixStr}`);
|
|
19
|
+
});
|
|
20
|
+
const highestVersionStr = versionToString(highestVersion);
|
|
21
|
+
const hotfixStr = highestVersion.hotfix ? ` (hotfix: ${highestVersion.hotfix})` : '';
|
|
22
|
+
consola.info(`Syncing all platforms to highest version: ${highestVersionStr}${hotfixStr}...`);
|
|
23
|
+
await versionService.setVersion(highestVersion);
|
|
24
|
+
consola.success(`All platforms synced to version ${highestVersionStr}${hotfixStr}`);
|
|
31
25
|
},
|
|
32
26
|
});
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import versionService from '../../../services/mutate/version.js';
|
|
2
|
+
import { CliError } from '../../../utils/error.js';
|
|
3
|
+
import consola from 'consola';
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
+
import syncCommand from './sync.js';
|
|
6
|
+
vi.mock('consola');
|
|
7
|
+
vi.mock('@/services/mutate/version.js');
|
|
8
|
+
describe('mutate:version:sync', () => {
|
|
9
|
+
const mockConsola = vi.mocked(consola);
|
|
10
|
+
const mockVersionService = vi.mocked(versionService);
|
|
11
|
+
const mockExit = vi.spyOn(process, 'exit').mockImplementation(() => undefined);
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
vi.clearAllMocks();
|
|
14
|
+
});
|
|
15
|
+
afterEach(() => {
|
|
16
|
+
vi.restoreAllMocks();
|
|
17
|
+
});
|
|
18
|
+
it('should sync to highest version across platforms', async () => {
|
|
19
|
+
const mockVersions = [
|
|
20
|
+
{
|
|
21
|
+
platform: 'ios',
|
|
22
|
+
version: { major: 1, minor: 2, patch: 3, hotfix: 0 },
|
|
23
|
+
source: 'ios/App/App.xcodeproj/project.pbxproj',
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
platform: 'android',
|
|
27
|
+
version: { major: 1, minor: 3, patch: 0, hotfix: 0 },
|
|
28
|
+
source: 'android/app/build.gradle',
|
|
29
|
+
},
|
|
30
|
+
{ platform: 'web', version: { major: 1, minor: 2, patch: 4 }, source: 'package.json' },
|
|
31
|
+
];
|
|
32
|
+
const highestVersion = { major: 1, minor: 3, patch: 0, hotfix: 0 };
|
|
33
|
+
mockVersionService.getAllVersions.mockResolvedValue(mockVersions);
|
|
34
|
+
mockVersionService.getHighestVersion.mockResolvedValue(highestVersion);
|
|
35
|
+
mockVersionService.setVersion.mockResolvedValue(undefined);
|
|
36
|
+
await syncCommand.action({}, undefined);
|
|
37
|
+
expect(mockConsola.info).toHaveBeenCalledWith('Current versions:');
|
|
38
|
+
expect(mockConsola.log).toHaveBeenCalledWith(' ios: 1.2.3');
|
|
39
|
+
expect(mockConsola.log).toHaveBeenCalledWith(' android: 1.3.0');
|
|
40
|
+
expect(mockConsola.log).toHaveBeenCalledWith(' web: 1.2.4');
|
|
41
|
+
expect(mockConsola.info).toHaveBeenCalledWith('Syncing all platforms to highest version: 1.3.0...');
|
|
42
|
+
expect(mockVersionService.setVersion).toHaveBeenCalledWith(highestVersion);
|
|
43
|
+
expect(mockConsola.success).toHaveBeenCalledWith('All platforms synced to version 1.3.0');
|
|
44
|
+
expect(mockExit).not.toHaveBeenCalled();
|
|
45
|
+
});
|
|
46
|
+
it('should sync including hotfix for iOS/Android', async () => {
|
|
47
|
+
const mockVersions = [
|
|
48
|
+
{
|
|
49
|
+
platform: 'ios',
|
|
50
|
+
version: { major: 1, minor: 2, patch: 3, hotfix: 5 },
|
|
51
|
+
source: 'ios/App/App.xcodeproj/project.pbxproj',
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
platform: 'android',
|
|
55
|
+
version: { major: 1, minor: 2, patch: 3, hotfix: 5 },
|
|
56
|
+
source: 'android/app/build.gradle',
|
|
57
|
+
},
|
|
58
|
+
{ platform: 'web', version: { major: 1, minor: 2, patch: 2 }, source: 'package.json' },
|
|
59
|
+
];
|
|
60
|
+
const highestVersion = { major: 1, minor: 2, patch: 3, hotfix: 5 };
|
|
61
|
+
mockVersionService.getAllVersions.mockResolvedValue(mockVersions);
|
|
62
|
+
mockVersionService.getHighestVersion.mockResolvedValue(highestVersion);
|
|
63
|
+
mockVersionService.setVersion.mockResolvedValue(undefined);
|
|
64
|
+
await syncCommand.action({}, undefined);
|
|
65
|
+
expect(mockConsola.log).toHaveBeenCalledWith(' ios: 1.2.3 (hotfix: 5)');
|
|
66
|
+
expect(mockConsola.log).toHaveBeenCalledWith(' android: 1.2.3 (hotfix: 5)');
|
|
67
|
+
expect(mockConsola.log).toHaveBeenCalledWith(' web: 1.2.2');
|
|
68
|
+
expect(mockConsola.info).toHaveBeenCalledWith('Syncing all platforms to highest version: 1.2.3 (hotfix: 5)...');
|
|
69
|
+
expect(mockConsola.success).toHaveBeenCalledWith('All platforms synced to version 1.2.3 (hotfix: 5)');
|
|
70
|
+
});
|
|
71
|
+
it('should handle no platform versions found', async () => {
|
|
72
|
+
mockVersionService.getAllVersions.mockResolvedValue([]);
|
|
73
|
+
await expect(syncCommand.action({}, undefined)).rejects.toThrow(CliError);
|
|
74
|
+
await expect(syncCommand.action({}, undefined)).rejects.toThrow('No platform versions found');
|
|
75
|
+
expect(mockVersionService.setVersion).not.toHaveBeenCalled();
|
|
76
|
+
});
|
|
77
|
+
it('should handle service errors', async () => {
|
|
78
|
+
const mockVersions = [
|
|
79
|
+
{
|
|
80
|
+
platform: 'ios',
|
|
81
|
+
version: { major: 1, minor: 2, patch: 3, hotfix: 0 },
|
|
82
|
+
source: 'ios/App/App.xcodeproj/project.pbxproj',
|
|
83
|
+
},
|
|
84
|
+
];
|
|
85
|
+
mockVersionService.getAllVersions.mockResolvedValue(mockVersions);
|
|
86
|
+
mockVersionService.getHighestVersion.mockRejectedValue(new Error('Failed to determine highest version'));
|
|
87
|
+
await expect(syncCommand.action({}, undefined)).rejects.toThrow('Failed to determine highest version');
|
|
88
|
+
expect(mockVersionService.setVersion).not.toHaveBeenCalled();
|
|
89
|
+
});
|
|
90
|
+
});
|
package/dist/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import configService from './services/config.js';
|
|
3
3
|
import updateService from './services/update.js';
|
|
4
|
-
import { getMessageFromUnknownError } from './utils/error.js';
|
|
4
|
+
import { CliError, getMessageFromUnknownError } from './utils/error.js';
|
|
5
5
|
import { defineConfig, processConfig, ZliError } from '@robingenz/zli';
|
|
6
6
|
import * as Sentry from '@sentry/node';
|
|
7
7
|
import { AxiosError } from 'axios';
|
|
8
8
|
import consola from 'consola';
|
|
9
|
-
import { ZodError } from 'zod';
|
|
10
9
|
import { createRequire } from 'module';
|
|
10
|
+
import { ZodError } from 'zod';
|
|
11
11
|
const require = createRequire(import.meta.url);
|
|
12
12
|
const pkg = require('../package.json');
|
|
13
13
|
const config = defineConfig({
|
|
@@ -44,10 +44,13 @@ const config = defineConfig({
|
|
|
44
44
|
},
|
|
45
45
|
});
|
|
46
46
|
const captureException = async (error) => {
|
|
47
|
-
// Ignore
|
|
47
|
+
// Ignore expected CLI errors (e.g. "No command found.")
|
|
48
48
|
if (error instanceof ZliError) {
|
|
49
49
|
return;
|
|
50
50
|
}
|
|
51
|
+
if (error instanceof CliError) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
51
54
|
// Ignore validation errors
|
|
52
55
|
if (error instanceof ZodError) {
|
|
53
56
|
return;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CliError } from '../../utils/error.js';
|
|
1
2
|
import { compareVersions, parseBuildNumber, parseVersion, versionToBuildNumber, versionToString, } from '../../utils/version.js';
|
|
2
3
|
import { MobileProject, Logger } from '@trapezedev/project';
|
|
3
4
|
import { existsSync, readFileSync } from 'fs';
|
|
@@ -165,7 +166,7 @@ export class VersionService {
|
|
|
165
166
|
const versions = await this.getAllVersions();
|
|
166
167
|
const firstVersion = versions && versions[0] ? versions[0].version : null;
|
|
167
168
|
if (!firstVersion) {
|
|
168
|
-
throw new
|
|
169
|
+
throw new CliError('No platform versions found');
|
|
169
170
|
}
|
|
170
171
|
// Check major.minor.patch synchronization for all platforms
|
|
171
172
|
const allVersionsInSync = versions.every((pv) => pv.version.major === firstVersion.major &&
|
|
@@ -177,7 +178,7 @@ export class VersionService {
|
|
|
177
178
|
const hotfixStr = pv.platform !== 'web' && pv.version.hotfix ? ` (hotfix: ${pv.version.hotfix})` : '';
|
|
178
179
|
return `${pv.platform}: ${versionStr}${hotfixStr} (${pv.source})`;
|
|
179
180
|
});
|
|
180
|
-
throw new
|
|
181
|
+
throw new CliError(`Versions are not synchronized across platforms:\n${versionStrings.join('\n')}`);
|
|
181
182
|
}
|
|
182
183
|
// Check hotfix synchronization between iOS and Android only
|
|
183
184
|
const iosVersion = versions.find((pv) => pv.platform === 'ios');
|
|
@@ -186,7 +187,7 @@ export class VersionService {
|
|
|
186
187
|
const iosHotfix = iosVersion.version.hotfix || 0;
|
|
187
188
|
const androidHotfix = androidVersion.version.hotfix || 0;
|
|
188
189
|
if (iosHotfix !== androidHotfix) {
|
|
189
|
-
throw new
|
|
190
|
+
throw new CliError(`Hotfix versions are not synchronized between iOS and Android:\n` +
|
|
190
191
|
`iOS: ${versionToString(iosVersion.version)} (hotfix: ${iosHotfix})\n` +
|
|
191
192
|
`Android: ${versionToString(androidVersion.version)} (hotfix: ${androidHotfix})`);
|
|
192
193
|
}
|
|
@@ -198,7 +199,7 @@ export class VersionService {
|
|
|
198
199
|
async getHighestVersion() {
|
|
199
200
|
const versions = await this.getAllVersions();
|
|
200
201
|
if (versions.length === 0) {
|
|
201
|
-
throw new
|
|
202
|
+
throw new CliError('No platform versions found');
|
|
202
203
|
}
|
|
203
204
|
let highest = versions[0];
|
|
204
205
|
for (const current of versions) {
|
package/dist/utils/error.js
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
import { AxiosError } from 'axios';
|
|
2
2
|
import { ZodError } from 'zod';
|
|
3
|
+
export class CliError extends Error {
|
|
4
|
+
constructor(message) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.name = 'CliError';
|
|
7
|
+
}
|
|
8
|
+
}
|
|
3
9
|
export const getMessageFromUnknownError = (error) => {
|
|
4
10
|
let message = 'An unknown error has occurred.';
|
|
5
|
-
if (error instanceof
|
|
11
|
+
if (error instanceof CliError) {
|
|
12
|
+
message = error.message;
|
|
13
|
+
}
|
|
14
|
+
else if (error instanceof AxiosError) {
|
|
6
15
|
message = getErrorMessageFromAxiosError(error);
|
|
7
16
|
}
|
|
8
17
|
else if (error instanceof ZodError) {
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { CliError, getMessageFromUnknownError } from './error.js';
|
|
3
|
+
describe('CliError', () => {
|
|
4
|
+
it('should be an instance of Error', () => {
|
|
5
|
+
const error = new CliError('Test error');
|
|
6
|
+
expect(error).toBeInstanceOf(Error);
|
|
7
|
+
expect(error).toBeInstanceOf(CliError);
|
|
8
|
+
});
|
|
9
|
+
it('should have the correct name', () => {
|
|
10
|
+
const error = new CliError('Test error');
|
|
11
|
+
expect(error.name).toBe('CliError');
|
|
12
|
+
});
|
|
13
|
+
it('should have the correct message', () => {
|
|
14
|
+
const message = 'This is a test error message';
|
|
15
|
+
const error = new CliError(message);
|
|
16
|
+
expect(error.message).toBe(message);
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
describe('getMessageFromUnknownError', () => {
|
|
20
|
+
it('should handle CliError correctly', () => {
|
|
21
|
+
const message = 'This is a CLI error';
|
|
22
|
+
const error = new CliError(message);
|
|
23
|
+
expect(getMessageFromUnknownError(error)).toBe(message);
|
|
24
|
+
});
|
|
25
|
+
it('should handle regular Error', () => {
|
|
26
|
+
const message = 'This is a regular error';
|
|
27
|
+
const error = new Error(message);
|
|
28
|
+
expect(getMessageFromUnknownError(error)).toBe(message);
|
|
29
|
+
});
|
|
30
|
+
it('should handle unknown error types', () => {
|
|
31
|
+
expect(getMessageFromUnknownError('string error')).toBe('An unknown error has occurred.');
|
|
32
|
+
expect(getMessageFromUnknownError(123)).toBe('An unknown error has occurred.');
|
|
33
|
+
expect(getMessageFromUnknownError(null)).toBe('An unknown error has occurred.');
|
|
34
|
+
expect(getMessageFromUnknownError(undefined)).toBe('An unknown error has occurred.');
|
|
35
|
+
});
|
|
36
|
+
});
|
package/package.json
CHANGED