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
5 changes: 5 additions & 0 deletions .changeset/remove-config-deprecation-warning.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@pull-up/cli': patch
---

Remove the deprecation warning for JavaScript and TypeScript configuration files.
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,7 @@ The path is relative to the YAML file. For Yarn Plug'n'Play or a remote schema,

### JavaScript and TypeScript Configuration

Starting in 0.0.8, JavaScript and TypeScript configuration files are deprecated. They continue to work, but pull-up prints one warning to stderr per command when it loads a `.js`, `.ts`, `.cjs`, or `.mjs` configuration file, including `.pulluprc` files with these extensions. See [Migration](#migration) to move to YAML.

The `package.json` `pullup` field and JSON/YAML `.pulluprc` configurations remain supported without this deprecation warning.
JavaScript and TypeScript configuration files are supported alongside YAML configuration.

Use `pullup.config.ts`, `pullup.config.js`, `pullup.config.cjs`, or `pullup.config.mjs` for a JavaScript or TypeScript configuration:

Expand Down
26 changes: 7 additions & 19 deletions src/core/config/resolve-config.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import path from 'node:path';

import { Fixture } from '@fixture-kit/core';

import { resolveConfig } from './resolve-config';
Expand Down Expand Up @@ -90,19 +88,14 @@ describe('resolveConfig', () => {
['.pulluprc.ts', tsConfig],
['.pulluprc.cjs', cjsConfig],
['.pulluprc.mjs', esmConfig],
])('resolves jobs from %s and warns about deprecation once', async (filename, contents) => {
])('resolves jobs from %s without a deprecation warning', async (filename, contents) => {
await using fixture = await Fixture.create({
'package.json': JSON.stringify({ type: 'module' }),
[filename]: contents,
});

expect(await resolveConfig(fixture.root)).toEqual(customJobs);
expect(console.warn).toHaveBeenCalledOnce();
expect(console.warn).toHaveBeenCalledWith(expect.stringContaining(path.join(fixture.root, filename)));
expect(console.warn).toHaveBeenCalledWith(expect.stringContaining('[DEPRECATED]'));
expect(console.warn).toHaveBeenCalledWith(expect.stringContaining('pullup.yml or pullup.yaml'));
expect(console.warn).toHaveBeenCalledWith(expect.stringContaining('external commands'));
expect(console.warn).toHaveBeenCalledWith(expect.stringContaining('https://github.com/toss/pull-up#migration'));
expect(console.warn).not.toHaveBeenCalled();
});

it.each([
Expand All @@ -120,22 +113,18 @@ describe('resolveConfig', () => {
expect(console.warn).not.toHaveBeenCalled();
});

it('warns about an empty JavaScript configuration', async () => {
it('resolves an empty JavaScript configuration without a deprecation warning', async () => {
await using fixture = await Fixture.create({ 'pullup.config.cjs': 'module.exports = [];' });

expect(await resolveConfig(fixture.root)).toEqual([]);
expect(console.warn).toHaveBeenCalledOnce();
expect(console.warn).toHaveBeenCalledWith(expect.stringContaining(path.join(fixture.root, 'pullup.config.cjs')));
expect(console.warn).not.toHaveBeenCalled();
});

it('warns about a script configuration discovered inside .config', async () => {
it('resolves a script configuration inside .config without a deprecation warning', async () => {
await using fixture = await Fixture.create({ '.config': { 'pulluprc.cjs': cjsConfig } });

expect(await resolveConfig(fixture.root)).toEqual(customJobs);
expect(console.warn).toHaveBeenCalledOnce();
expect(console.warn).toHaveBeenCalledWith(
expect.stringContaining(path.join(fixture.root, '.config', 'pulluprc.cjs')),
);
expect(console.warn).not.toHaveBeenCalled();
});

it('resolves jobs from package.json#pullup', async () => {
Expand Down Expand Up @@ -175,8 +164,7 @@ describe('resolveConfig', () => {
'pullup.yml': 'jobs: []\n',
});
expect(await resolveConfig(fixture.root)).toEqual(customJobs);
expect(console.warn).toHaveBeenCalledOnce();
expect(console.warn).toHaveBeenCalledWith(expect.stringContaining(path.join(fixture.root, 'pullup.config.js')));
expect(console.warn).not.toHaveBeenCalled();
});

it('prefers package.json over pullup.config.js', async () => {
Expand Down
15 changes: 0 additions & 15 deletions src/core/config/resolve-config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import path from 'node:path';
import { styleText } from 'node:util';

import { cosmiconfig, getDefaultSearchPlaces } from 'cosmiconfig';
import * as v from 'valibot';
Expand All @@ -23,20 +22,6 @@ export async function resolveConfig(cwd: string): Promise<Job[]> {
return toJobs(v.parse(ConfigSchema, result.config));
}

if (['.js', '.ts', '.cjs', '.mjs'].includes(path.extname(result.filepath))) {
console.warn(
styleText(
'yellow',
[
`[DEPRECATED] JavaScript/TypeScript configuration is deprecated: ${result.filepath}`,
'Use pullup.yml or pullup.yaml for built-in jobs and external commands for custom transforms.',
'Migration guide: https://github.com/toss/pull-up#migration',
'',
].join('\n'),
),
);
}

return result.config as Job[];
}

Expand Down
22 changes: 5 additions & 17 deletions tests/codeowners-cli.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,6 @@ const config = `import { codeownersJob } from ${JSON.stringify(CORE_URL)};
export default [codeownersJob()];
`;

function expectScriptConfigWarning(result: { stdout: string; stderr: string }, configPath: string) {
expect(result.stderr).toBe(
`[DEPRECATED] JavaScript/TypeScript configuration is deprecated: ${configPath}\n` +
'Use pullup.yml or pullup.yaml for built-in jobs and external commands for custom transforms.\n' +
'Migration guide: https://github.com/toss/pull-up#migration\n\n',
);
expect(result.stderr.match(/\[DEPRECATED\]/g)).toHaveLength(1);
expect(result.stdout).not.toContain('[DEPRECATED]');
}

describe('codeowners-cli', () => {
it.each([
{ name: 'the repository root', cwd: 'repo', explicitRoot: false },
Expand Down Expand Up @@ -55,15 +45,13 @@ describe('codeowners-cli', () => {
const options: string[] = [];
if (scenario.explicitRoot) options.push('--root', rootDir);
if (scenario.explicitCwd === true) options.push('--cwd', subdirectory);
const configDirectory = scenario.explicitCwd === true ? subdirectory : path.join(fixture.root, scenario.cwd);
const configPath = path.join(configDirectory, 'pullup.config.mjs');

const sync = await execFileAsync(process.execPath, [CLI_PATH, 'sync', ...options], {
cwd: path.join(fixture.root, scenario.cwd),
timeout: 10_000,
});
expect(sync.stdout).toContain('codeowners synced');
expectScriptConfigWarning(sync, configPath);
expect(sync.stderr).toBe('');

expect(await readFile(path.join(rootDir, '.github/CODEOWNERS'), 'utf8')).toBe(
'* @root-team\n' +
Expand All @@ -85,7 +73,7 @@ describe('codeowners-cli', () => {
timeout: 10_000,
});
expect(check.stdout).toContain('All files are up to date');
expectScriptConfigWarning(check, configPath);
expect(check.stderr).toBe('');

if (scenario.explicitRoot || scenario.explicitCwd === true) {
await expect(readFile(path.join(otherRoot, '.github/CODEOWNERS'), 'utf8')).rejects.toMatchObject({
Expand Down Expand Up @@ -117,7 +105,7 @@ export default [codeownersJob({ input: ${JSON.stringify(scenario.input)} })];
timeout: 10_000,
});

expectScriptConfigWarning(sync, path.join(rootDir, 'pullup.config.mjs'));
expect(sync.stderr).toBe('');
expect(await readFile(path.join(rootDir, '.github/CODEOWNERS'), 'utf8')).toBe(
'/services/auth/ @auth-team\n' + '/services/auth/login/ @login-team\n',
);
Expand All @@ -138,7 +126,7 @@ export default [codeownersJob({ input: ${JSON.stringify(scenario.input)} })];
const sync = await execFileAsync(process.execPath, [CLI_PATH, 'sync'], { cwd: fixture.root, timeout: 10_000 });

expect(sync.stdout).toContain('codeowners synced');
expectScriptConfigWarning(sync, path.join(fixture.root, 'pullup.config.mjs'));
expect(sync.stderr).toBe('');
expect(await readFile(path.join(fixture.root, '.github/CODEOWNERS'), 'utf8')).toBe(
'*.js @root-team\n' +
'/packages/web/**/*.ts @frontend-team\n' +
Expand All @@ -150,6 +138,6 @@ export default [codeownersJob({ input: ${JSON.stringify(scenario.input)} })];
const check = await execFileAsync(process.execPath, [CLI_PATH, 'check'], { cwd: fixture.root, timeout: 10_000 });

expect(check.stdout).toContain('All files are up to date');
expectScriptConfigWarning(check, path.join(fixture.root, 'pullup.config.mjs'));
expect(check.stderr).toBe('');
});
});
23 changes: 6 additions & 17 deletions tests/config-cli.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,6 @@ const config = `jobs:
output: .github/CODEOWNERS
`;

function scriptConfigWarning(configPath: string) {
return (
`[DEPRECATED] JavaScript/TypeScript configuration is deprecated: ${configPath}\n` +
'Use pullup.yml or pullup.yaml for built-in jobs and external commands for custom transforms.\n' +
'Migration guide: https://github.com/toss/pull-up#migration\n\n'
);
}

function runCli(command: string, rootDir: string, args: string[] = []) {
return execFileAsync(process.execPath, [CLI_PATH, command, ...args], {
cwd: rootDir,
Expand Down Expand Up @@ -145,17 +137,16 @@ describe('YAML config CLI', () => {
const result = await runCli(command, fixture.root);

expect(result.code).toBe(0);
expect(result.stderr).toBe(scriptConfigWarning(path.join(fixture.root, 'pullup.config.mjs')));
expect(result.stderr.match(/\[DEPRECATED\]/g)).toHaveLength(1);
expect(result.stderr).toBe('');
expect(result.stdout).not.toContain('[DEPRECATED]');
expect(result.stdout).toContain(command === 'sync' ? 'custom synced' : 'All files are up to date');
expect(await readFile(path.join(fixture.root, '.github/CODEOWNERS'), 'utf8')).toBe(generatedContents);
});
});
});

describe('script config CLI deprecation warning', () => {
it('warns once for sync --dry-run while preserving the preview and existing output', async () => {
describe('script config CLI', () => {
it('previews sync --dry-run without warnings or changing the existing output', async () => {
await using fixture = await Fixture.create({
'.git': {},
'pullup.config.mjs': scriptConfig,
Expand All @@ -165,16 +156,15 @@ describe('script config CLI deprecation warning', () => {
const result = await runCli('sync', fixture.root, ['--dry-run']);

expect(result.code).toBe(0);
expect(result.stderr).toBe(scriptConfigWarning(path.join(fixture.root, 'pullup.config.mjs')));
expect(result.stderr.match(/\[DEPRECATED\]/g)).toHaveLength(1);
expect(result.stderr).toBe('');
expect(result.stdout).not.toContain('[DEPRECATED]');
expect(result.stdout).toContain('[Job] custom');
expect(result.stdout).toContain('Output: .github/CODEOWNERS');
expect(result.stdout).toContain(generatedContents.trimEnd());
expect(await readFile(path.join(fixture.root, '.github/CODEOWNERS'), 'utf8')).toBe(existingContents);
});

it('warns once without changing the outdated check failure or existing output', async () => {
it('reports an outdated check failure without deprecation warnings or changing the existing output', async () => {
await using fixture = await Fixture.create({
'.git': {},
'pullup.config.mjs': scriptConfig,
Expand All @@ -184,8 +174,7 @@ describe('script config CLI deprecation warning', () => {
const result = await runCli('check', fixture.root);

expect(result.code).toBe(1);
expect(result.stderr).toContain(scriptConfigWarning(path.join(fixture.root, 'pullup.config.mjs')));
expect(result.stderr.match(/\[DEPRECATED\]/g)).toHaveLength(1);
expect(result.stderr).not.toContain('[DEPRECATED]');
expect(result.stderr).toContain("custom is outdated. Run 'pullup sync' to update.");
expect(result.stdout).toBe('');
expect(await readFile(path.join(fixture.root, '.github/CODEOWNERS'), 'utf8')).toBe(existingContents);
Expand Down
24 changes: 4 additions & 20 deletions tests/output-read-errors.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,6 @@ const config = `export default [
];
`;

function scriptConfigWarning(rootDir: string) {
return (
`[DEPRECATED] JavaScript/TypeScript configuration is deprecated: ${path.join(rootDir, 'pullup.config.mjs')}\n` +
'Use pullup.yml or pullup.yaml for built-in jobs and external commands for custom transforms.\n' +
'Migration guide: https://github.com/toss/pull-up#migration\n\n'
);
}

function expectScriptConfigWarning(result: { stdout: string; stderr: string }, rootDir: string) {
expect(result.stderr).toContain(scriptConfigWarning(rootDir));
expect(result.stderr.match(/\[DEPRECATED\]/g)).toHaveLength(1);
expect(result.stdout).not.toContain('[DEPRECATED]');
}

async function prepareRepository(rootDir: string) {
await mkdir(path.join(rootDir, '.git'));
await mkdir(path.join(rootDir, '.github'), { recursive: true });
Expand Down Expand Up @@ -58,7 +44,7 @@ describe('output read errors', () => {
const result = await runCli(command, fixture.root);

expect(result.code).toBe(1);
expectScriptConfigWarning(result, fixture.root);
expect(result.stdout + result.stderr).not.toContain('[DEPRECATED]');
expect(result.stdout + result.stderr).toContain('EISDIR');
expect(result.stdout + result.stderr).toContain(outputPath);
expect(result.stdout + result.stderr).not.toContain('outdated');
Expand All @@ -81,7 +67,7 @@ describe('output read errors', () => {
const result = await runCli(command, fixture.root);

expect(result.code).toBe(1);
expectScriptConfigWarning(result, fixture.root);
expect(result.stdout + result.stderr).not.toContain('[DEPRECATED]');
expect(result.stdout + result.stderr).toContain('EACCES');
expect(result.stdout + result.stderr).toContain(outputPath);
expect(result.stdout + result.stderr).not.toContain('outdated');
Expand All @@ -103,16 +89,14 @@ describe('output read errors', () => {
const sync = await runCli('sync', fixture.root);

expect(sync.code).toBe(0);
expect(sync.stderr).toBe(scriptConfigWarning(fixture.root));
expectScriptConfigWarning(sync, fixture.root);
expect(sync.stderr).toBe('');
expect(sync.stdout).toContain('unreadable synced');
expect(await readFile(path.join(fixture.root, output), 'utf8')).toBe('generated output\n');

const check = await runCli('check', fixture.root);

expect(check.code).toBe(0);
expect(check.stderr).toBe(scriptConfigWarning(fixture.root));
expectScriptConfigWarning(check, fixture.root);
expect(check.stderr).toBe('');
expect(check.stdout).toContain('All files are up to date');
});
});
Loading