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
62 changes: 62 additions & 0 deletions packages/makage/__tests__/updateDeps.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,68 @@ describe('runUpdateDeps', () => {
expect(result.has_dep_changes).toBe(false);
});

it('should scan all package.json files in non-workspace target repos', async () => {
// Source workspace has one package
mockedFs.readFile.mockImplementation(async (filePath: any) => {
const p = filePath.toString();
if (p.endsWith('pnpm-workspace.yaml') && p.includes('source')) {
return WORKSPACE_YAML;
}
if (p.endsWith('pnpm-workspace.yaml') && p.includes('boilerplate')) {
throw new Error('ENOENT');
}
// Source package
if (p.includes('source') && p.includes('packages/foo/package.json')) {
return makePkg('@scope/foo', '3.0.0');
}
// Boilerplate target — multiple independent package.json files, no workspace
if (p.includes('boilerplate') && p.includes('graphql/codegen/package.json')) {
return makePkg('codegen-template', '0.0.1', { '@scope/foo': '^2.0.0' });
}
if (p.includes('boilerplate') && p.includes('nextjs/app/package.json')) {
return makePkg('nextjs-template', '0.0.1', {}, { '@scope/foo': '^3.0.0' });
}
if (p.includes('boilerplate') && p.endsWith('package.json') && !p.includes('graphql') && !p.includes('nextjs')) {
return makePkg('boilerplate-root', '1.0.0');
}
throw new Error(`ENOENT: ${p}`);
});

mockedGlob.mockImplementation(async (patterns: any, opts: any) => {
const cwd = opts?.cwd || '';
if (cwd.includes('source')) {
return ['packages/foo/package.json'];
}
// Non-workspace target — glob returns all nested package.json files
if (cwd.includes('boilerplate')) {
return ['package.json', 'graphql/codegen/package.json', 'nextjs/app/package.json'];
}
return [];
});

const result = await runUpdateDeps(['--from', '/source', '--in', '/boilerplate']);

// Should find the source package
expect(result.sourcePackages).toHaveLength(1);
expect(result.sourcePackages[0].name).toBe('@scope/foo');

// Should match deps in both nested templates (not root — root has no matching deps)
expect(result.matchedPackages).toHaveLength(2);

// codegen-template has @scope/foo ^2.0.0 -> 3.0.0 (outdated)
const codegenMatch = result.matchedPackages.find(p => p.consumer === 'codegen-template');
expect(codegenMatch?.outdated).toBe(true);
expect(codegenMatch?.depType).toBe('dependencies');

// nextjs-template has @scope/foo ^3.0.0 -> 3.0.0 (up to date)
const nextjsMatch = result.matchedPackages.find(p => p.consumer === 'nextjs-template');
expect(nextjsMatch?.outdated).toBe(false);
expect(nextjsMatch?.depType).toBe('devDependencies');

expect(result.has_dep_changes).toBe(true);
expect(result.outdatedPackages).toHaveLength(1);
});

it('should handle workspace: protocol as not outdated', async () => {
mockedFs.readFile.mockImplementation(async (filePath: any) => {
const p = filePath.toString();
Expand Down
14 changes: 13 additions & 1 deletion packages/makage/src/commands/updateDeps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,19 @@ async function getTargetPackageFiles(targetRoot: string): Promise<string[]> {
// Not a monorepo — fall through
}

return ['package.json'];
// No workspace — scan for all package.json files recursively
const allFiles = await glob('**/package.json', {
cwd: targetRoot,
absolute: false,
ignore: ['**/node_modules/**']
});

// Always include root package.json first if it exists
if (allFiles.includes('package.json')) {
return ['package.json', ...allFiles.filter(f => f !== 'package.json')];
}

return allFiles.length > 0 ? allFiles : ['package.json'];
}

export async function runUpdateDeps(args: string[]): Promise<UpdateDepsResult> {
Expand Down
Loading