Skip to content
Merged
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
3 changes: 2 additions & 1 deletion packages/notes/tsup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ export default defineConfig({
format: ['esm'],
dts: { resolve: ['@releasekit/core', '@releasekit/config', '@releasekit/forge', '@releasekit/git'] },
noExternal: ['@releasekit/core', '@releasekit/config', '@releasekit/forge', '@releasekit/git'],
external: [/^[^.]/],
// Externalize npm packages, but not the bundled @releasekit/* or local files (relative or absolute paths).
external: [/^(?![./]|[A-Za-z]:[\\/]|@releasekit\/)/],
});
5 changes: 4 additions & 1 deletion packages/publish/src/registry/cargo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,9 @@ export const cargoRegistry: Registry<CargoTarget, CargoSession> = {
},
};

function findCrates(updates: Array<{ newVersion: string; filePath: string; dir: string }>): CargoTarget[] {
function findCrates(
updates: Array<{ packageName: string; newVersion: string; filePath: string; dir: string }>,
): CargoTarget[] {
const crates: CargoTarget[] = [];

for (const update of updates) {
Expand All @@ -137,6 +139,7 @@ function findCrates(updates: Array<{ newVersion: string; filePath: string; dir:

crates.push({
packageName: cargo.package.name,
updatePackageName: update.packageName,
version: update.newVersion,
dir: update.dir,
manifestPath: cargoPath,
Expand Down
1 change: 1 addition & 0 deletions packages/publish/src/registry/dispatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export async function runPublishStage<T extends RegistryTarget, S>(
for (const target of targets) {
const result: PublishResult = {
packageName: target.packageName,
updatePackageName: target.updatePackageName,
version: target.version,
registry: registry.id,
success: false,
Expand Down
1 change: 1 addition & 0 deletions packages/publish/src/registry/npm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ export const npmRegistry: Registry<NpmTarget, NpmSession> = {
async discover(ctx: PipelineContext): Promise<NpmTarget[]> {
const targets = ctx.input.updates.map((u) => ({
packageName: u.packageName,
updatePackageName: u.packageName,
version: u.newVersion,
filePath: u.filePath,
}));
Expand Down
5 changes: 4 additions & 1 deletion packages/publish/src/registry/pub.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,9 @@ export const pubRegistry: Registry<PubTarget, void> = {
},
};

function findPubPackages(updates: Array<{ newVersion: string; filePath: string; dir: string }>): PubTarget[] {
function findPubPackages(
updates: Array<{ packageName: string; newVersion: string; filePath: string; dir: string }>,
): PubTarget[] {
const packages: PubTarget[] = [];
const seen = new Set<string>();

Expand All @@ -106,6 +108,7 @@ function findPubPackages(updates: Array<{ newVersion: string; filePath: string;

packages.push({
packageName: pubspec.name,
updatePackageName: update.packageName,
version: update.newVersion,
dir: update.dir,
command: detectPubCommand(pubspec.environment as Record<string, unknown> | undefined),
Expand Down
2 changes: 2 additions & 0 deletions packages/publish/src/registry/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ export type RegistryId = 'npm' | 'cargo' | 'pub';
/** The minimum a publishable unit must expose for the shared dispatcher. */
export interface RegistryTarget {
packageName: string;
/** The name in `VersionOutput`. Some crates and Dart packages have a different registry `packageName`. */
updatePackageName: string;
version: string;
}

Expand Down
2 changes: 2 additions & 0 deletions packages/publish/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ export interface PublishCliOptions {

export interface PublishResult {
packageName: string;
/** The name in `VersionOutput`. Some crates and Dart packages have a different registry `packageName`. */
updatePackageName: string;
version: string;
registry: 'npm' | 'cargo' | 'pub';
success: boolean;
Expand Down
19 changes: 19 additions & 0 deletions packages/publish/test/unit/stages/pub-publish.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,25 @@ describe('pub-publish stage', () => {
expect(ctx.output.pub[0]?.success).toBe(true);
});

it("should record a hybrid package's result under its update's name", async () => {
const dir = createTmpDir();
const pkgDir = path.join(dir, 'packages', 'my-package');
fs.mkdirSync(pkgDir, { recursive: true });
writePubspec(pkgDir, 'my_package');

const ctx = createContext(dir, {
input: {
dryRun: false,
updates: [{ packageName: 'my-package', newVersion: '0.5.0', filePath: 'packages/my-package/package.json' }],
changelogs: [],
tags: [],
},
});
await runPubPublishStage(ctx);

expect(ctx.output.pub[0]).toMatchObject({ packageName: 'my_package', updatePackageName: 'my-package' });
});

it('should publish a package only once when multiple updates share the same dir', async () => {
const { execCommand } = await import('../../../src/utils/exec.js');
const dir = createTmpDir();
Expand Down
3 changes: 2 additions & 1 deletion packages/publish/tsup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ export default defineConfig({
format: ['esm'],
dts: { resolve: ['@releasekit/core', '@releasekit/config', '@releasekit/git'] },
noExternal: ['@releasekit/core', '@releasekit/config', '@releasekit/git'],
external: [/^[^.]/],
// Externalize npm packages, but not the bundled @releasekit/* or local files (relative or absolute paths).
external: [/^(?![./]|[A-Za-z]:[\\/]|@releasekit\/)/],
});
14 changes: 7 additions & 7 deletions packages/release/src/commands/backfill-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,17 +89,17 @@ export function createBackfillCommand(): Command {
const updateReleases: boolean = options.updateReleases === true;
const onlyMissing: boolean = options.onlyMissing === true;
const notesConfig = loadNotesConfig(cwd, options.config);
const publishConfig = loadPublishConfig(cwd, options.config);
const releaseNotesEnabled = notesConfig.releaseNotes !== false && notesConfig.releaseNotes !== undefined;
const dir = releaseNotesEnabled ? notesConfig.releaseNotes?.file?.dir : undefined;
const publishConfig = loadPublishConfig({ cwd, configPath: options.config });
const releaseNotes = notesConfig.releaseNotes === false ? undefined : notesConfig.releaseNotes;
const dir = releaseNotes?.file?.dir;
if (!dir && !updateReleases) {
error(
'Backfill needs an output: pass --update-releases to update GitHub release bodies, or set ' +
'notes.releaseNotes.file.dir to write per-version files.',
);
process.exit(EXIT_CODES.GENERAL_ERROR);
}
if (updateReleases && !releaseNotesEnabled) {
if (updateReleases && !releaseNotes) {
error('--update-releases needs notes.releaseNotes enabled in your config to render the bodies.');
process.exit(EXIT_CODES.GENERAL_ERROR);
}
Expand Down Expand Up @@ -147,9 +147,9 @@ export function createBackfillCommand(): Command {
}

// Estimate and warn about LLM cost if not in --no-llm mode and LLM is enabled
const llmEnabled = !noLlm && notesConfig.releaseNotes?.llm;
const llmEnabled = !noLlm && releaseNotes?.llm;
if (llmEnabled && totalReleaseCount > 0) {
const llmConfig = notesConfig.releaseNotes?.llm;
const llmConfig = releaseNotes?.llm;
const enabledTasks = countEnabledLlmTasks(llmConfig?.tasks);
warn(
`Estimated cost: ~${totalReleaseCount} release(s) × ${enabledTasks} LLM task(s). ` +
Expand Down Expand Up @@ -196,7 +196,7 @@ export function createBackfillCommand(): Command {

// Override LLM config if --no-llm is set
const adjustedNotesConfig = noLlm
? { ...notesConfig, releaseNotes: { ...notesConfig.releaseNotes, llm: undefined } }
? { ...notesConfig, releaseNotes: { ...releaseNotes, llm: undefined } }
: notesConfig;

// Render one version per pipeline call (single context each). The pipeline's nesting decision
Expand Down
14 changes: 7 additions & 7 deletions packages/release/src/failure-report/failure-report.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { markerData, type VersionOutput } from '@releasekit/core';
import type { PublishOutput } from '@releasekit/publish';
import type { PublishOutput, PublishResult } from '@releasekit/publish';
import { ATTRIBUTION_FOOTER } from '../attribution.js';
import { publishableUpdates, syncVersionDisplay } from '../version-display.js';

Expand Down Expand Up @@ -71,8 +71,8 @@ export interface LedgerEntry {
packageName: string;
version: string;
status: LedgerStatus;
/** Registry the result came from (npm/cargo), when known. */
registry?: 'npm' | 'cargo';
/** Registry the result came from, when known. */
registry?: PublishResult['registry'];
/** Human-readable detail — the skip reason or failure reason. */
detail?: string;
}
Expand Down Expand Up @@ -101,7 +101,7 @@ const STATUS_LABEL: Record<LedgerStatus, string> = {
*/
export function buildLedger(versionOutput: VersionOutput, publishOutput: PublishOutput | undefined): LedgerEntry[] {
const updates = publishableUpdates(versionOutput);
const results = [...(publishOutput?.npm ?? []), ...(publishOutput?.cargo ?? [])];
const results = [...(publishOutput?.npm ?? []), ...(publishOutput?.cargo ?? []), ...(publishOutput?.pub ?? [])];
Comment thread
greptile-apps[bot] marked this conversation as resolved.
Resolved

// Index results by package name. A package may appear once (single registry) — when it appears
// on multiple registries, prefer a failed/published entry over a skipped one so the headline
Expand All @@ -120,9 +120,9 @@ export function buildLedger(versionOutput: VersionOutput, publishOutput: Publish
status = 'published';
}

const existing = byPackage.get(r.packageName);
const existing = byPackage.get(r.updatePackageName);
const entry: LedgerEntry = {
packageName: r.packageName,
packageName: r.updatePackageName,
version: r.version,
status,
registry: r.registry,
Expand All @@ -131,7 +131,7 @@ export function buildLedger(versionOutput: VersionOutput, publishOutput: Publish
// Significance order: failed > published > skipped. Keep the more significant outcome.
const significance: Record<LedgerStatus, number> = { failed: 3, published: 2, skipped: 1, 'not-attempted': 0 };
if (!existing || significance[status] > significance[existing.status]) {
byPackage.set(r.packageName, entry);
byPackage.set(r.updatePackageName, entry);
}
}

Expand Down
30 changes: 30 additions & 0 deletions packages/release/test/unit/commands/backfill-command.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { afterEach, describe, expect, it, vi } from 'vitest';

vi.mock('@releasekit/version', () => ({ loadConfig: vi.fn() }));
vi.mock('@releasekit/notes', () => ({
loadConfig: vi.fn(() => ({ releaseNotes: false })),
runPipeline: vi.fn(),
versionOutputToChangelogInput: vi.fn(),
}));
vi.mock('@releasekit/publish', () => ({ loadConfig: vi.fn(() => ({ githubRelease: {} })) }));

import { loadConfig as loadPublishConfig } from '@releasekit/publish';
import { createBackfillCommand } from '../../../src/commands/backfill-command.js';

describe('backfill command', () => {
afterEach(() => {
vi.restoreAllMocks();
});

it('should load the publish config from --config', async () => {
vi.spyOn(process, 'exit').mockImplementation(() => {
throw new Error('exit');
});

await expect(createBackfillCommand().parseAsync(['--config', 'custom.json'], { from: 'user' })).rejects.toThrow(
'exit',
);

expect(loadPublishConfig).toHaveBeenCalledWith({ cwd: process.cwd(), configPath: 'custom.json' });
});
});
29 changes: 26 additions & 3 deletions packages/release/test/unit/failure-report-post.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,23 @@ function publishOutputFor(npm: PublishResult[]): PublishOutput {

function pipelineErrorFor(versionOutput: VersionOutput): PipelineError {
const publishOutput = publishOutputFor([
{ packageName: '@scope/a', version: '0.24.0', registry: 'npm', success: true, skipped: false },
{ packageName: '@scope/b', version: '0.24.0', registry: 'npm', success: false, skipped: false, reason: 'npm 403' },
{
packageName: '@scope/a',
updatePackageName: '@scope/a',
version: '0.24.0',
registry: 'npm',
success: true,
skipped: false,
},
{
packageName: '@scope/b',
updatePackageName: '@scope/b',
version: '0.24.0',
registry: 'npm',
success: false,
skipped: false,
reason: 'npm 403',
},
]);
void versionOutput;
return new PipelineError('Failed to publish to npm: npm 403', 'npm-publish', publishOutput);
Expand Down Expand Up @@ -135,9 +150,17 @@ describe('detectUnresolvedFailure', () => {
const report = renderFailureReport({
versionOutput,
publishOutput: publishOutputFor([
{ packageName: '@scope/a', version: '0.24.0', registry: 'npm', success: true, skipped: false },
{
packageName: '@scope/a',
updatePackageName: '@scope/a',
version: '0.24.0',
registry: 'npm',
success: true,
skipped: false,
},
{
packageName: '@scope/b',
updatePackageName: '@scope/b',
version: '0.24.0',
registry: 'npm',
success: false,
Expand Down
31 changes: 30 additions & 1 deletion packages/release/test/unit/failure-report.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ function versionOutputFor(
function npmResult(partial: Partial<PublishResult> & { packageName: string; version: string }): PublishResult {
return {
registry: 'npm',
updatePackageName: partial.packageName,
success: true,
skipped: false,
...partial,
Expand Down Expand Up @@ -99,11 +100,39 @@ describe('buildLedger', () => {
npmResult({ packageName: '@scope/a', version: '1.0.0', success: true, alreadyPublished: true }),
]);
publishOutput.cargo = [
{ packageName: '@scope/a', version: '1.0.0', registry: 'cargo', success: false, skipped: false, reason: 'boom' },
{
packageName: '@scope/a',
updatePackageName: '@scope/a',
version: '1.0.0',
registry: 'cargo',
success: false,
skipped: false,
reason: 'boom',
},
];
const ledger = buildLedger(versionOutput, publishOutput);
expect(ledger[0]?.status).toBe('failed');
});

it("should match a hybrid package's pub.dev result by its update's name", () => {
const versionOutput = versionOutputFor([{ name: 'my-package', version: '1.0.0' }]);
const publishOutput = publishOutputFor([npmResult({ packageName: 'my-package', version: '1.0.0' })]);
publishOutput.pub = [
{
packageName: 'my_package',
updatePackageName: 'my-package',
version: '1.0.0',
registry: 'pub',
success: false,
skipped: false,
reason: 'boom',
},
];

expect(buildLedger(versionOutput, publishOutput)).toEqual([
{ packageName: 'my-package', version: '1.0.0', status: 'failed', registry: 'pub', detail: 'boom' },
]);
});
});

describe('renderFailureReport', () => {
Expand Down
10 changes: 9 additions & 1 deletion packages/release/test/unit/standing-pr.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1722,9 +1722,17 @@ describe('runStandingPRUpdate', () => {
dryRun: false,
git: { committed: true, tags: [], pushed: false },
npm: [
{ packageName: '@scope/core', version: '0.24.0', registry: 'npm', success: true, skipped: false },
{
packageName: '@scope/core',
updatePackageName: '@scope/core',
version: '0.24.0',
registry: 'npm',
success: true,
skipped: false,
},
{
packageName: '@scope/utils',
updatePackageName: '@scope/utils',
version: '0.24.0',
registry: 'npm',
success: false,
Expand Down
5 changes: 4 additions & 1 deletion packages/release/tsup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ var require = __createRequire(import.meta.url);`.trim(),
format: ['esm'],
platform: 'node',
bundle: true,
dts: false,
dts: {
entry: 'src/index.ts',
resolve: ['@releasekit/core', '@releasekit/config', '@releasekit/forge', '@releasekit/git'],
},
minify: false,
splitting: false,
external: ['minimatch'],
Expand Down
3 changes: 2 additions & 1 deletion packages/version/tsup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ export default defineConfig({
bundle: true,
dts: { resolve: ['@releasekit/core', '@releasekit/config', '@releasekit/git'] },
noExternal: ['@releasekit/core', '@releasekit/config', '@releasekit/git'],
external: [/^[^.]/],
// Externalize npm packages, but not the bundled @releasekit/* or local files (relative or absolute paths).
external: [/^(?![./]|[A-Za-z]:[\\/]|@releasekit\/)/],
} as Options);
Loading
Loading