Skip to content
Draft
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
192 changes: 192 additions & 0 deletions packages/api/cli/spec/args-parsing.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
import { describe, expect, it } from 'vitest';

import { getMakeOptions } from '../src/electron-forge-make.js';
import { getPackageOptions } from '../src/electron-forge-package.js';
import { getPublishOptions } from '../src/electron-forge-publish.js';
import { getStartOptions } from '../src/electron-forge-start.js';

// Commander expects argv in the format [execPath, scriptPath, ...args]
const argv = (args: string[]) => ['node', 'test', ...args];

describe('getMakeOptions', () => {
it('defaults arch to process.arch', () => {
const opts = getMakeOptions(argv([]));
expect(opts.arch).toBe(process.arch);
});

it('defaults platform to process.platform', () => {
const opts = getMakeOptions(argv([]));
expect(opts.platform).toBe(process.platform);
});

it('parses --arch flag', () => {
const opts = getMakeOptions(argv(['--arch', 'arm64']));
expect(opts.arch).toBe('arm64');
});

it('parses -a shorthand', () => {
const opts = getMakeOptions(argv(['-a', 'ia32']));
expect(opts.arch).toBe('ia32');
});

it('parses --platform flag', () => {
const opts = getMakeOptions(argv(['--platform', 'linux']));
expect(opts.platform).toBe('linux');
});

it('parses --targets as comma-separated list', () => {
const opts = getMakeOptions(argv(['--targets', 'deb,rpm']));
expect(opts.overrideTargets).toEqual(['deb', 'rpm']);
});

it('sets skipPackage when --skip-package is passed', () => {
const opts = getMakeOptions(argv(['--skip-package']));
expect(opts.skipPackage).toBe(true);
});

it('does not set overrideTargets by default', () => {
const opts = getMakeOptions(argv([]));
expect(opts.overrideTargets).toBeUndefined();
});

it('always sets interactive to true', () => {
const opts = getMakeOptions(argv([]));
expect(opts.interactive).toBe(true);
});

it('defaults dir to cwd when no dir argument', () => {
const opts = getMakeOptions(argv([]));
expect(opts.dir).toBe(process.cwd());
});
});

describe('getPackageOptions', () => {
it('defaults dir to cwd when no dir argument', () => {
const opts = getPackageOptions(argv([]));
expect(opts.dir).toBe(process.cwd());
});

it('parses --arch flag', () => {
const opts = getPackageOptions(argv(['--arch', 'arm64']));
expect(opts.arch).toBe('arm64');
});

it('parses --platform flag', () => {
const opts = getPackageOptions(argv(['--platform', 'win32']));
expect(opts.platform).toBe('win32');
});

it('does not set arch/platform by default', () => {
const opts = getPackageOptions(argv([]));
expect(opts.arch).toBeUndefined();
expect(opts.platform).toBeUndefined();
});

it('always sets interactive to true', () => {
const opts = getPackageOptions(argv([]));
expect(opts.interactive).toBe(true);
});
});

describe('getPublishOptions', () => {
it('defaults dir to cwd when no dir argument', () => {
const opts = getPublishOptions(argv([]));
expect(opts.dir).toBe(process.cwd());
});

it('parses --target flag as comma-separated list', () => {
const opts = getPublishOptions(argv(['--target', 'github,s3']));
expect(opts.publishTargets).toEqual(['github', 's3']);
});

it('sets dryRun with --dry-run', () => {
const opts = getPublishOptions(argv(['--dry-run']));
expect(opts.dryRun).toBe(true);
});

it('sets dryRunResume with --from-dry-run', () => {
const opts = getPublishOptions(argv(['--from-dry-run']));
expect(opts.dryRunResume).toBe(true);
});

it('does not set publishTargets by default', () => {
const opts = getPublishOptions(argv([]));
expect(opts.publishTargets).toBeUndefined();
});

it('includes makeOptions from getMakeOptions', () => {
const opts = getPublishOptions(argv(['--arch', 'arm64']));
expect(opts.makeOptions).toBeDefined();
expect(opts.makeOptions!.arch).toBe('arm64');
});
});

describe('getStartOptions', () => {
it('defaults dir to cwd when no dir argument', () => {
const opts = getStartOptions(argv([]));
expect(opts.dir).toBe(process.cwd());
});

it('parses --enable-logging flag', () => {
const opts = getStartOptions(argv(['--enable-logging']));
expect(opts.enableLogging).toBe(true);
});

it('parses -l shorthand for enable-logging', () => {
const opts = getStartOptions(argv(['-l']));
expect(opts.enableLogging).toBe(true);
});

it('parses --run-as-node flag', () => {
const opts = getStartOptions(argv(['--run-as-node']));
expect(opts.runAsNode).toBe(true);
});

it('parses --inspect-electron flag', () => {
const opts = getStartOptions(argv(['--inspect-electron']));
expect(opts.inspect).toBe(true);
});

it('parses --inspect-brk-electron flag', () => {
const opts = getStartOptions(argv(['--inspect-brk-electron']));
expect(opts.inspectBrk).toBe(true);
});

it('parses --app-path option', () => {
const opts = getStartOptions(argv(['--app-path', '/some/path']));
expect(opts.appPath).toBe('/some/path');
});

it('passes args after -- as app args', () => {
const opts = getStartOptions(argv(['--', '-d', '-f', 'foo.txt']));
expect(opts.args).toEqual(['-d', '-f', 'foo.txt']);
});

it('separates command args from app args', () => {
const opts = getStartOptions(
argv(['--enable-logging', '--', '--app-flag']),
);
expect(opts.enableLogging).toBe(true);
expect(opts.args).toEqual(['--app-flag']);
});

it('strips ~ wrappers from app args with --vscode', () => {
const opts = getStartOptions(
argv(['--vscode', '--', '~--some-arg~', '~~']),
);
expect(opts.args).toEqual(['--some-arg']);
});

it('defaults boolean flags to false', () => {
const opts = getStartOptions(argv([]));
expect(opts.enableLogging).toBe(false);
expect(opts.runAsNode).toBe(false);
expect(opts.inspect).toBe(false);
expect(opts.inspectBrk).toBe(false);
});

it('always sets interactive to true', () => {
const opts = getStartOptions(argv([]));
expect(opts.interactive).toBe(true);
});
});
21 changes: 12 additions & 9 deletions packages/api/cli/src/electron-forge-make.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import url from 'node:url';

import { initializeProxy } from '@electron/get';
import { api, MakeOptions } from '@electron-forge/core';
import type { MakeOptions } from '@electron-forge/core';
import { resolveWorkingDir } from '@electron-forge/core-utils';
import chalk from 'chalk';
import { program } from 'commander';
import { createCommand } from 'commander';

import './util/terminate.js';
import packageJSON from '../package.json' with { type: 'json' };

export async function getMakeOptions(): Promise<MakeOptions> {
export function getMakeOptions(argv: string[]): MakeOptions {
let workingDir: string;
program
const cmd = createCommand();
cmd
.version(
packageJSON.version,
'-V, --version',
Expand Down Expand Up @@ -40,9 +39,9 @@ export async function getMakeOptions(): Promise<MakeOptions> {
.action((dir) => {
workingDir = resolveWorkingDir(dir, false);
})
.parse(process.argv);
.parse(argv);

const options = program.opts();
const options = cmd.opts();

const makeOpts: MakeOptions = {
dir: workingDir!,
Expand All @@ -64,7 +63,11 @@ if (import.meta.url.startsWith('file:')) {
const modulePath = url.fileURLToPath(import.meta.url);
if (process.argv[1] === modulePath) {
(async () => {
const makeOpts = await getMakeOptions();
await import('./util/terminate.js');
const { initializeProxy } = await import('@electron/get');
const { api } = await import('@electron-forge/core');

const makeOpts = getMakeOptions(process.argv);

initializeProxy();

Expand Down
71 changes: 46 additions & 25 deletions packages/api/cli/src/electron-forge-package.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,55 @@
import { initializeProxy } from '@electron/get';
import { api, PackageOptions } from '@electron-forge/core';
import url from 'node:url';

import type { PackageOptions } from '@electron-forge/core';
import { resolveWorkingDir } from '@electron-forge/core-utils';
import { program } from 'commander';
import { createCommand } from 'commander';

import './util/terminate.js';
import packageJSON from '../package.json' with { type: 'json' };

program
.version(packageJSON.version, '-V, --version', 'Output the current version')
.helpOption('-h, --help', 'Output usage information')
.argument(
'[dir]',
'Directory to run the command in. (default: current directory)',
)
.option('-a, --arch [arch]', 'Target build architecture')
.option('-p, --platform [platform]', 'Target build platform')
.action(async (dir) => {
const workingDir = resolveWorkingDir(dir);
export function getPackageOptions(argv: string[]): PackageOptions {
let workingDir: string;
const cmd = createCommand();
cmd
.version(packageJSON.version, '-V, --version', 'Output the current version')
.helpOption('-h, --help', 'Output usage information')
.argument(
'[dir]',
'Directory to run the command in. (default: current directory)',
)
.option('-a, --arch [arch]', 'Target build architecture')
.option('-p, --platform [platform]', 'Target build platform')
.action((dir) => {
workingDir = resolveWorkingDir(dir);
})
.parse(argv);

const options = program.opts();
const options = cmd.opts();

initializeProxy();
const packageOpts: PackageOptions = {
dir: workingDir!,
interactive: true,
};
if (options.arch) packageOpts.arch = options.arch;
if (options.platform) packageOpts.platform = options.platform;

return packageOpts;
}

const packageOpts: PackageOptions = {
dir: workingDir,
interactive: true,
};
if (options.arch) packageOpts.arch = options.arch;
if (options.platform) packageOpts.platform = options.platform;
// NOTE: this is a hack that exists because Node.js didn't add import.meta.main
// support until 22.18.0. We should bump up the engines and get that fix before
// we go to stable.
// ref https://2ality.com/2022/07/nodejs-esm-main.html
if (import.meta.url.startsWith('file:')) {
const modulePath = url.fileURLToPath(import.meta.url);
if (process.argv[1] === modulePath) {
await import('./util/terminate.js');
const { initializeProxy } = await import('@electron/get');
const { api } = await import('@electron-forge/core');

const packageOpts = getPackageOptions(process.argv);

initializeProxy();

await api.package(packageOpts);
})
.parse(process.argv);
}
}
Loading
Loading