Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/commands/apps/bundles/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,18 @@ export default defineCommand({
.describe(
'A custom property to assign to the bundle. Must be in the format `key=value`. Can be specified multiple times.',
),
electronMax: z
.string()
.optional()
.describe('The maximum Electron app version (`app.getVersion()`) that the bundle supports.'),
electronMin: z
.string()
.optional()
.describe('The minimum Electron app version (`app.getVersion()`) that the bundle supports.'),
electronEq: z
.string()
.optional()
.describe('The exact Electron app version (`app.getVersion()`) that the bundle does not support.'),
expiresInDays: z.coerce
.number({
message: 'Expiration days must be an integer.',
Expand Down
12 changes: 12 additions & 0 deletions src/commands/apps/bundles/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,18 @@ export default defineCommand({
})
.optional()
.describe('The percentage of devices to deploy the bundle to. Must be a number between 0 and 1 (e.g. 0.5).'),
electronMax: z
.string()
.optional()
.describe('The maximum Electron app version (`app.getVersion()`) that the bundle supports.'),
electronMin: z
.string()
.optional()
.describe('The minimum Electron app version (`app.getVersion()`) that the bundle supports.'),
electronEq: z
.string()
.optional()
.describe('The exact Electron app version (`app.getVersion()`) that the bundle should not support.'),
iosMax: z
.string()
.optional()
Expand Down
45 changes: 45 additions & 0 deletions src/commands/apps/liveupdates/register.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,51 @@ describe('apps-liveupdates-register', () => {
expect(mockConsola.success).toHaveBeenCalledWith('Live Update successfully registered.');
});

it('should pass Electron version constraints to API when provided', async () => {
const appId = 'app-123';
const bundleUrl = 'https://example.com/bundle.zip';
const bundleId = 'bundle-456';
const testToken = 'test-token';
const electronEq = '1.0.0';
const electronMin = '2.0.0';
const electronMax = '3.0.0';

const options = {
appId,
url: bundleUrl,
rolloutPercentage: 1,
electronEq,
electronMin,
electronMax,
yes: true,
};

const appScope = nock(DEFAULT_API_BASE_URL)
.get(`/v1/apps/${appId}`)
.matchHeader('Authorization', `Bearer ${testToken}`)
.reply(200, { id: appId, name: 'Test App' });

const bundleScope = nock(DEFAULT_API_BASE_URL)
.post(`/v1/apps/${appId}/bundles`, {
appId,
url: bundleUrl,
artifactType: 'zip',
eqElectronAppVersionCode: electronEq,
minElectronAppVersionCode: electronMin,
maxElectronAppVersionCode: electronMax,
rolloutPercentage: 0.01,
})
.matchHeader('Authorization', `Bearer ${testToken}`)
.reply(201, { id: bundleId, appBuildId: 'build-789' });

await registerCommand.action(options, undefined);

expect(appScope.isDone()).toBe(true);
expect(bundleScope.isDone()).toBe(true);
expect(mockConsola.info).toHaveBeenCalledWith(`Bundle Artifact ID: ${bundleId}`);
expect(mockConsola.success).toHaveBeenCalledWith('Live Update successfully registered.');
});

it('should register bundle with checksum when path is provided', async () => {
const appId = 'app-123';
const bundleUrl = 'https://example.com/bundle.zip';
Expand Down
18 changes: 18 additions & 0 deletions src/commands/apps/liveupdates/register.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,18 @@ export default defineCommand({
.describe(
'A custom property to assign to the bundle. Must be in the format `key=value`. Can be specified multiple times.',
),
electronMax: z
.string()
.optional()
.describe('The maximum Electron app version (`app.getVersion()`) that the bundle supports.'),
electronMin: z
Comment thread
robingenz marked this conversation as resolved.
.string()
.optional()
.describe('The minimum Electron app version (`app.getVersion()`) that the bundle supports.'),
electronEq: z
.string()
.optional()
.describe('The exact Electron app version (`app.getVersion()`) that the bundle does not support.'),
expiresInDays: z.coerce
.number({
message: 'Expiration days must be an integer.',
Expand Down Expand Up @@ -122,6 +134,9 @@ export default defineCommand({
commitRef,
commitSha,
customProperty,
electronEq,
electronMax,
electronMin,
expiresInDays,
gitRef,
iosEq,
Expand Down Expand Up @@ -268,6 +283,7 @@ export default defineCommand({
channelName: channel,
checksum,
eqAndroidAppVersionCode: androidEq,
eqElectronAppVersionCode: electronEq,
eqIosAppVersionCode: iosEq,
gitCommitMessage: commitMessage,
gitCommitRef: commitRef,
Expand All @@ -276,8 +292,10 @@ export default defineCommand({
customProperties: parseCustomProperties(customProperty),
url,
maxAndroidAppVersionCode: androidMax,
maxElectronAppVersionCode: electronMax,
maxIosAppVersionCode: iosMax,
minAndroidAppVersionCode: androidMin,
minElectronAppVersionCode: electronMin,
minIosAppVersionCode: iosMin,
rolloutPercentage: (rolloutPercentage ?? 100) / 100,
signature,
Expand Down
71 changes: 71 additions & 0 deletions src/commands/apps/liveupdates/upload.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,77 @@ describe('apps-liveupdates-upload', () => {
expect(mockConsola.success).toHaveBeenCalledWith('Live Update successfully uploaded.');
});

it('should pass Electron version constraints to API when provided', async () => {
const appId = 'app-123';
const bundlePath = './dist';
const bundleId = 'bundle-456';
const testToken = 'test-token';
const testBuffer = Buffer.from('test');
const electronEq = '1.0.0';
const electronMin = '2.0.0';
const electronMax = '3.0.0';

const options = {
appId,
path: bundlePath,
artifactType: 'zip' as const,
rollout: 1,
electronEq,
electronMin,
electronMax,
};

mockIsReadable.mockResolvedValue(true);
mockIsDirectory.mockResolvedValue(true);
mockGetFilesInDirectoryAndSubdirectories.mockResolvedValue([
{ href: 'index.html', mimeType: 'text/html', name: 'index.html', path: 'index.html' },
]);

// Mock utility functions
const mockZip = await import('@/utils/zip.js');
const mockHash = await import('@/utils/hash.js');

vi.mocked(mockZip.default.isZipped).mockReturnValue(false);
vi.mocked(mockZip.default.zipFolder).mockResolvedValue(testBuffer);
vi.mocked(mockHash.createHash).mockResolvedValue('test-hash');

const appScope = nock(DEFAULT_API_BASE_URL)
.get(`/v1/apps/${appId}`)
.matchHeader('Authorization', `Bearer ${testToken}`)
.reply(200, { id: appId, name: 'Test App' });

const bundleScope = nock(DEFAULT_API_BASE_URL)
.post(`/v1/apps/${appId}/bundles`, {
appId,
artifactType: 'zip',
eqElectronAppVersionCode: electronEq,
minElectronAppVersionCode: electronMin,
maxElectronAppVersionCode: electronMax,
rolloutPercentage: 1,
})
.matchHeader('Authorization', `Bearer ${testToken}`)
.reply(201, { id: bundleId, appBuildId: 'build-789' });

const uploadScope = nock(DEFAULT_API_BASE_URL)
.post(`/v1/apps/${appId}/bundles/${bundleId}/files`)
.matchHeader('Authorization', `Bearer ${testToken}`)
.reply(201, { id: 'file-123' });

const updateScope = nock(DEFAULT_API_BASE_URL)
.patch(`/v1/apps/${appId}/bundles/${bundleId}`)
.matchHeader('Authorization', `Bearer ${testToken}`)
.reply(200, { id: bundleId });

await uploadCommand.action(options, undefined);

expect(appScope.isDone()).toBe(true);
expect(bundleScope.isDone()).toBe(true);
expect(uploadScope.isDone()).toBe(true);
expect(updateScope.isDone()).toBe(true);
expect(mockConsola.info).toHaveBeenCalledWith(`Build Artifact ID: ${bundleId}`);
expect(mockConsola.success).toHaveBeenCalledWith('Live Update successfully uploaded.');
});

it('should output JSON when json flag is set', async () => {
const appId = 'app-123';
const bundlePath = './dist';
Expand Down
18 changes: 18 additions & 0 deletions src/commands/apps/liveupdates/upload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,18 @@ export default defineCommand({
.describe(
'A custom property to assign to the bundle. Must be in the format `key=value`. Can be specified multiple times.',
),
electronMax: z
.string()
.optional()
.describe('The maximum Electron app version (`app.getVersion()`) that the bundle supports.'),
electronMin: z
Comment thread
robingenz marked this conversation as resolved.
.string()
.optional()
.describe('The minimum Electron app version (`app.getVersion()`) that the bundle supports.'),
electronEq: z
.string()
.optional()
.describe('The exact Electron app version (`app.getVersion()`) that the bundle does not support.'),
expiresInDays: z.coerce
.number({
message: 'Expiration days must be an integer.',
Expand Down Expand Up @@ -148,6 +160,9 @@ export default defineCommand({
commitRef,
commitSha,
customProperty,
electronEq,
electronMax,
electronMin,
expiresInDays,
gitRef,
iosEq,
Expand Down Expand Up @@ -311,15 +326,18 @@ export default defineCommand({
artifactType,
channelName: channel,
eqAndroidAppVersionCode: androidEq,
eqElectronAppVersionCode: electronEq,
eqIosAppVersionCode: iosEq,
gitCommitMessage: commitMessage,
gitCommitRef: commitRef,
gitCommitSha: commitSha,
gitRef,
customProperties: parseCustomProperties(customProperty),
maxAndroidAppVersionCode: androidMax,
maxElectronAppVersionCode: electronMax,
maxIosAppVersionCode: iosMax,
minAndroidAppVersionCode: androidMin,
minElectronAppVersionCode: electronMin,
minIosAppVersionCode: iosMin,
// Convert percentage from 0-100 to 0-1 for API
rolloutPercentage: (rolloutPercentage ?? 100) / 100,
Expand Down
6 changes: 6 additions & 0 deletions src/types/app-bundle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export interface CreateAppBundleDto {
channelName?: string;
checksum?: string;
eqAndroidAppVersionCode?: string;
eqElectronAppVersionCode?: string;
eqIosAppVersionCode?: string;
gitCommitMessage?: string;
gitCommitRef?: string;
Expand All @@ -19,8 +20,10 @@ export interface CreateAppBundleDto {
expiresAt?: string;
url?: string;
maxAndroidAppVersionCode?: string;
maxElectronAppVersionCode?: string;
maxIosAppVersionCode?: string;
minAndroidAppVersionCode?: string;
minElectronAppVersionCode?: string;
minIosAppVersionCode?: string;
rolloutPercentage?: number;
signature?: string;
Expand All @@ -37,10 +40,13 @@ export interface UpdateAppBundleDto {
appId: string;
artifactStatus?: 'pending' | 'ready';
maxAndroidAppVersionCode?: string;
maxElectronAppVersionCode?: string;
maxIosAppVersionCode?: string;
minAndroidAppVersionCode?: string;
minElectronAppVersionCode?: string;
minIosAppVersionCode?: string;
eqAndroidAppVersionCode?: string;
eqElectronAppVersionCode?: string;
eqIosAppVersionCode?: string;
rolloutPercentage?: number;
}
Loading