fix: Support workspaces in CLIs

Signed-off-by: Gabriel Dugny <gabriel.dugny@believe.com>
This commit is contained in:
Gabriel Dugny
2026-01-29 10:24:31 +01:00
parent ebd4630702
commit a9d23c4a32
13 changed files with 79 additions and 62 deletions
+2 -1
View File
@@ -14,6 +14,7 @@
* limitations under the License.
*/
import { getWorkspacesPatterns } from '@backstage/cli-common';
import { paths } from '../paths';
import fs from 'fs-extra';
@@ -26,7 +27,7 @@ export async function isMonoRepo(): Promise<boolean> {
const rootPackageJsonPath = paths.resolveTargetRoot('package.json');
try {
const pkg = await fs.readJson(rootPackageJsonPath);
return Boolean(pkg?.workspaces?.packages);
return getWorkspacesPatterns(pkg).length > 0;
} catch (error) {
return false;
}
@@ -43,7 +43,7 @@ describe('PackageManager', () => {
expect(mockYarnCreate).toHaveBeenCalled();
});
it('should detect via root package.json workspaces', async () => {
it('should detect via root package.json workspaces with legacy workspaces.packages field', async () => {
mockDir.setContent({
'package.json': JSON.stringify({
name: 'foo',
@@ -55,6 +55,16 @@ describe('PackageManager', () => {
await detectPackageManager();
expect(mockYarnCreate).toHaveBeenCalled();
});
it('should detect via root package.json workspaces', async () => {
mockDir.setContent({
'package.json': JSON.stringify({
name: 'foo',
workspaces: [],
}),
});
await detectPackageManager();
expect(mockYarnCreate).toHaveBeenCalled();
});
it('should detect via root package.json packageManager', async () => {
mockDir.setContent({
@@ -17,7 +17,7 @@
import { Yarn } from './yarn';
import { Lockfile } from './Lockfile';
import { paths } from '../paths';
import { RunOptions } from '@backstage/cli-common';
import { getWorkspacesPatterns, RunOptions } from '@backstage/cli-common';
import fs from 'fs-extra';
/**
@@ -101,7 +101,7 @@ export async function detectPackageManager(): Promise<PackageManager> {
const packageJson = await fs.readJson(
paths.resolveTargetRoot('package.json'),
);
if (packageJson.workspaces) {
if (getWorkspacesPatterns(packageJson).length > 0) {
// technically this could be NPM as well
return await Yarn.create();
}
+10 -1
View File
@@ -30,7 +30,7 @@ const allYarnVersions = [yarnClassic, yarnBerry];
describe('Yarn', () => {
describe.each(allYarnVersions)('%s.getMonorepoPackages', yarn => {
it('should detect a monorepo', async () => {
it('should detect a monorepo with workspaces.packages field', async () => {
mockDir.setContent({
'package.json': JSON.stringify({
name: 'foo',
@@ -41,6 +41,15 @@ describe('Yarn', () => {
});
await expect(yarn.getMonorepoPackages()).resolves.toEqual(['packages/*']);
});
it('should detect a monorepo', async () => {
mockDir.setContent({
'package.json': JSON.stringify({
name: 'foo',
workspaces: ['packages/*'],
}),
});
await expect(yarn.getMonorepoPackages()).resolves.toEqual(['packages/*']);
});
it('should detect a non-monorepo', async () => {
mockDir.setContent({
+2 -1
View File
@@ -25,6 +25,7 @@ import { YarnVersion } from './types';
import fs from 'fs-extra';
import { paths } from '../../paths';
import { run, runOutput, RunOptions } from '@backstage/cli-common';
import { getWorkspacesPatterns } from '@backstage/cli-common';
export class Yarn implements PackageManager {
constructor(private readonly yarnVersion: YarnVersion) {}
@@ -50,7 +51,7 @@ export class Yarn implements PackageManager {
const rootPackageJsonPath = paths.resolveTargetRoot('package.json');
try {
const pkg = await fs.readJson(rootPackageJsonPath);
return pkg?.workspaces?.packages || [];
return getWorkspacesPatterns(pkg);
} catch (error) {
return [];
}