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
8 changes: 8 additions & 0 deletions packages/api/cli/spec/cli.slow.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,12 @@ describe('cli', () => {
it('should fail on unknown subcommands', async () => {
await expect(runForgeCLI('nonexistent')).rejects.toThrow(Error);
});

it('should list the release command in help output', async () => {
await expect(runForgeCLI('help')).resolves.toMatch(/\brelease\b/);
});

it('should hide the deprecated publish alias from help output', async () => {
await expect(runForgeCLI('help')).resolves.not.toMatch(/\bpublish\b/);
});
});
61 changes: 17 additions & 44 deletions packages/api/cli/src/electron-forge-publish.ts
Original file line number Diff line number Diff line change
@@ -1,48 +1,21 @@
import url from 'node:url';
import { styleText } from 'node:util';

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

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

import { getMakeOptions } from './electron-forge-make.js';

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(
'--target [target[,target...]]',
'A comma-separated list of deployment targets. (default: all publishers in your Forge config)',
)
.option(
'--dry-run',
`Run the ${styleText('green', 'make')} command and save publish metadata without uploading anything.`,
)
.option('--from-dry-run', 'Publish artifacts from the last saved dry run.')
.allowUnknownOption(true)
.action(async (targetDir) => {
const dir = resolveWorkingDir(targetDir);
const options = program.opts();

initializeProxy();

const publishOpts: PublishOptions = {
dir,
interactive: true,
dryRun: options.dryRun,
dryRunResume: options.fromDryRun,
};
if (options.target) publishOpts.publishTargets = options.target.split(',');

publishOpts.makeOptions = await getMakeOptions();

await api.publish(publishOpts);
})
.parse(process.argv);
import { runRelease } from './electron-forge-release.js';

// `electron-forge publish` is a deprecated alias for `electron-forge release`.
// It keeps working for now but prints a deprecation warning to stderr and
// delegates to the exact same behavior as `release`.
if (import.meta.url.startsWith('file:')) {
const modulePath = url.fileURLToPath(import.meta.url);
if (process.argv[1] === modulePath) {
console.error(
styleText('yellow', '⚠'),
'`electron-forge publish` is deprecated and will be removed in a future major version; use `electron-forge release` instead.',
);

await runRelease();
}
}
67 changes: 67 additions & 0 deletions packages/api/cli/src/electron-forge-release.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import url from 'node:url';
import { styleText } from 'node:util';

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

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

import { getMakeOptions } from './electron-forge-make.js';

export async function runRelease(): Promise<void> {
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(
'--target [target[,target...]]',
'A comma-separated list of deployment targets. (default: all publishers in your Forge config)',
)
.option(
'--dry-run',
`Run the ${styleText('green', 'make')} command and save release metadata without uploading anything.`,
)
.option('--from-dry-run', 'Release artifacts from the last saved dry run.')
.allowUnknownOption(true)
.action(async (targetDir) => {
const dir = resolveWorkingDir(targetDir);
const options = program.opts();

initializeProxy();

const releaseOpts: ReleaseOptions = {
dir,
interactive: true,
dryRun: options.dryRun,
dryRunResume: options.fromDryRun,
};
if (options.target)
releaseOpts.publishTargets = options.target.split(',');

releaseOpts.makeOptions = await getMakeOptions();

await api.release(releaseOpts);
})
.parse(process.argv);
}

// 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 runRelease();
}
}
8 changes: 7 additions & 1 deletion packages/api/cli/src/electron-forge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,13 @@ program
'make',
'Generate distributables for the current Electron application.',
)
.command('publish', 'Publish the current Electron application.')
.command('release', 'Release the current Electron application.')
// `publish` is a deprecated alias for `release`. It is hidden from the help
// output and prints a deprecation warning when invoked (see
// electron-forge-publish.ts).
.command('publish', 'Publish the current Electron application.', {
hidden: true,
})
.passThroughOptions(true)
.hook('preSubcommand', async (_command, subcommand) => {
if (!process.argv.includes('--help') && !process.argv.includes('-h')) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest';

import { listrMake } from '../../src/api/make';
import publish from '../../src/api/publish';
import release from '../../src/api/release';
import findConfig from '../../src/util/forge-config.js';
import { importSearch } from '../../src/util/import-search.js';

Expand Down Expand Up @@ -45,9 +45,9 @@ vi.mock(import('../../src/util/import-search'), async (importOriginal) => {
};
});

describe('publish', () => {
describe('release', () => {
it('calls "make"', async () => {
await publish({
await release({
dir: import.meta.dirname,
interactive: false,
});
Expand Down Expand Up @@ -79,7 +79,7 @@ describe('publish', () => {
} as any;
});

await publish({
await release({
dir: import.meta.dirname,
interactive: false,
});
Expand Down Expand Up @@ -109,7 +109,7 @@ describe('publish', () => {
{} as unknown as ResolvedForgeConfig,
);

await publish({
await release({
dir: import.meta.dirname,
interactive: false,
publishTargets: [new MockPublisher()],
Expand All @@ -134,7 +134,7 @@ describe('publish', () => {

vi.mocked(importSearch).mockResolvedValue(MockPublisher);

await publish({
await release({
dir: import.meta.dirname,
interactive: false,
});
Expand Down Expand Up @@ -172,7 +172,7 @@ describe('publish', () => {
});

it('dryRun creates hash JSON files', async () => {
await publish({
await release({
dir: import.meta.dirname,
outDir: tmpDir,
interactive: false,
Expand Down Expand Up @@ -203,7 +203,7 @@ describe('publish', () => {
MockPublisher.prototype.publish = mockPublish;
MockPublisher.prototype.__isElectronForgePublisher = true;

await publish({
await release({
dir: import.meta.dirname,
outDir: tmpDir,
interactive: false,
Expand Down
24 changes: 20 additions & 4 deletions packages/api/core/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,15 @@ import ForgeUtils from '../util/index.js';

import make, { MakeOptions } from './make.js';
import _package, { PackageOptions } from './package.js';
import publish, { PublishOptions } from './publish.js';
import release, { ReleaseOptions } from './release.js';
import start, { StartOptions } from './start.js';

/**
* @deprecated Use {@link ReleaseOptions} instead. `PublishOptions` is a
* deprecated alias that will be removed in a future major version.
*/
export type PublishOptions = ReleaseOptions;

export class ForgeAPI {
/**
* Make distributables for an Electron application
Expand All @@ -26,11 +32,21 @@ export class ForgeAPI {
return _package(opts);
}

/**
* Release an Electron application into the given target service
*/
release(opts: ReleaseOptions): Promise<void> {
return release(opts);
}

/**
* Publish an Electron application into the given target service
*
* @deprecated Use {@link ForgeAPI.release} instead. `publish` is a deprecated
* alias that will be removed in a future major version.
*/
publish(opts: PublishOptions): Promise<void> {
return publish(opts);
publish(opts: ReleaseOptions): Promise<void> {
return release(opts);
}

/**
Expand All @@ -53,7 +69,7 @@ export {
ForgeUtils,
MakeOptions,
PackageOptions,
PublishOptions,
ReleaseOptions,
StartOptions,
api,
utils,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,16 @@ import resolveDir from '../util/resolve-dir.js';

import { listrMake, MakeOptions } from './make.js';

const d = debug('electron-forge:publish');
const d = debug('electron-forge:release');

type PublishContext = {
type ReleaseContext = {
dir: string;
forgeConfig: ResolvedForgeConfig;
publishers: PublisherBase<unknown>[];
makeResults: ForgeMakeResult[];
};

export interface PublishOptions {
export interface ReleaseOptions {
/**
* The path to the app to be published
*/
Expand Down Expand Up @@ -70,7 +70,7 @@ export interface PublishOptions {
}

export default autoTrace(
{ name: 'publish()', category: '@electron-forge/core' },
{ name: 'release()', category: '@electron-forge/core' },
async (
childTrace,
{
Expand All @@ -81,13 +81,13 @@ export default autoTrace(
dryRun = false,
dryRunResume = false,
outDir,
}: PublishOptions,
}: ReleaseOptions,
): Promise<void> => {
if (dryRun && dryRunResume) {
throw new Error("Can't dry run and resume a dry run at the same time");
}

const listrOptions: ForgeListrOptions<PublishContext> = {
const listrOptions: ForgeListrOptions<ReleaseContext> = {
concurrent: false,
rendererOptions: {
collapseErrors: false,
Expand All @@ -100,12 +100,12 @@ export default autoTrace(
const publishDistributablesTasks = (childTrace: typeof autoTrace) => [
{
title: 'Publishing distributables',
task: childTrace<Parameters<ForgeListrTaskFn<PublishContext>>>(
task: childTrace<Parameters<ForgeListrTaskFn<ReleaseContext>>>(
{ name: 'publish-distributables', category: '@electron-forge/core' },
async (
childTrace,
{ dir, forgeConfig, makeResults, publishers },
task: ForgeListrTask<PublishContext>,
task: ForgeListrTask<ReleaseContext>,
) => {
if (publishers.length === 0) {
task.output = 'No publishers configured';
Expand Down Expand Up @@ -156,11 +156,11 @@ export default autoTrace(
},
];

const runner = new Listr<PublishContext>(
const runner = new Listr<ReleaseContext>(
[
{
title: 'Loading configuration',
task: childTrace<Parameters<ForgeListrTaskFn<PublishContext>>>(
task: childTrace<Parameters<ForgeListrTaskFn<ReleaseContext>>>(
{ name: 'load-forge-config', category: '@electron-forge/core' },
async (childTrace, ctx) => {
const resolvedDir = await resolveDir(providedDir);
Expand All @@ -177,7 +177,7 @@ export default autoTrace(
},
{
title: 'Resolving publish targets',
task: childTrace<Parameters<ForgeListrTaskFn<PublishContext>>>(
task: childTrace<Parameters<ForgeListrTaskFn<ReleaseContext>>>(
{
name: 'resolve-publish-targets',
category: '@electron-forge/core',
Expand Down Expand Up @@ -252,7 +252,7 @@ export default autoTrace(
title: dryRunResume
? 'Resuming from dry run...'
: `Running ${styleText('yellow', 'make')} command`,
task: childTrace<Parameters<ForgeListrTaskFn<PublishContext>>>(
task: childTrace<Parameters<ForgeListrTaskFn<ReleaseContext>>>(
{
name: dryRunResume ? 'resume-dry-run' : 'make()',
category: '@electron-forge/core',
Expand All @@ -276,12 +276,12 @@ export default autoTrace(

return delayTraceTillSignal(
childTrace,
task.newListr<PublishContext>(
task.newListr<ReleaseContext>(
publishes.map((publishStates, index) => {
return {
title: `Publishing dry-run ${styleText('blue', `#${index + 1}`)}`,
task: childTrace<
Parameters<ForgeListrTaskFn<PublishContext>>
Parameters<ForgeListrTaskFn<ReleaseContext>>
>(
{
name: `publish-dry-run-${index + 1}`,
Expand Down Expand Up @@ -371,7 +371,7 @@ export default autoTrace(
{
title: 'Saving dry-run state',
task: childTrace<
Parameters<ForgeListrTaskFn<PublishContext>>
Parameters<ForgeListrTaskFn<ReleaseContext>>
>(
{ name: 'save-dry-run', category: '@electron-forge/core' },
async (childTrace, { dir, forgeConfig, makeResults }) => {
Expand Down
Loading
Loading