Skip to content

Commit

Permalink
feat(commonality): Adds workspaces property to project configuration (
Browse files Browse the repository at this point in the history
  • Loading branch information
alec-chernicki authored Jan 30, 2024
1 parent 70dcda0 commit 0508b8f
Show file tree
Hide file tree
Showing 21 changed files with 194 additions and 111 deletions.
7 changes: 7 additions & 0 deletions .changeset/silver-bees-bake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@commonalityco/data-project": patch
"@commonalityco/utils-core": patch
"commonality": patch
---

Adds a `workspaces` property to the project configuration file. This will allow you to override your package manager's workspaces. This will also allow integrated monorepos to filter packages without adding a workspaces property to their package manager.
4 changes: 2 additions & 2 deletions apps/commonality/src/define-config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ProjectConfig } from '@commonalityco/utils-core';
import { ProjectConfigInput } from '@commonalityco/utils-core';

export function defineConfig(config: ProjectConfig): ProjectConfig {
export function defineConfig(config: ProjectConfigInput): ProjectConfigInput {
return config;
}
4 changes: 2 additions & 2 deletions packages/data-constraints/src/get-constraint-results.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Dependency, TagsData, ConstraintResult } from '@commonalityco/types';
import { ProjectConfig } from '@commonalityco/utils-core';
import { ProjectConfigOutput } from '@commonalityco/utils-core';

const edgeKey = (dep: Dependency) => `${dep.source}|${dep.target}`;

Expand Down Expand Up @@ -108,7 +108,7 @@ export async function getConstraintResults({
dependencies = [],
tagsData = [],
}: {
constraints?: ProjectConfig['constraints'];
constraints?: ProjectConfigOutput['constraints'];
dependencies: Dependency[];
tagsData: TagsData[];
}): Promise<ConstraintResult[]> {
Expand Down
4 changes: 3 additions & 1 deletion packages/data-project/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@
"@commonalityco/config-tsconfig": "workspace:*",
"@commonalityco/types": "workspace:*",
"@types/fs-extra": "^11.0.2",
"@types/mock-fs": "^4.13.4",
"@types/node": "^20.10.0",
"eslint-config-commonality": "workspace:*",
"mock-fs": "^5.2.0",
"typescript": "^5.2.2"
},
"dependencies": {
Expand All @@ -48,4 +50,4 @@
"url": "https://github.com/commonalityco/commonality",
"directory": "packages/data-project"
}
}
}
13 changes: 9 additions & 4 deletions packages/data-project/src/get-project-config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import jiti from 'jiti';
import { findUp } from 'find-up';
import { ProjectConfig, projectConfigSchema } from '@commonalityco/utils-core';
import { ZodError } from 'zod';
import {
ProjectConfigOutput,
projectConfigSchema,
} from '@commonalityco/utils-core';
import z, { ZodError } from 'zod';

Check warning on line 7 in packages/data-project/src/get-project-config.ts

View workflow job for this annotation

GitHub Actions / lint

'z' is defined but never used

Check warning on line 7 in packages/data-project/src/get-project-config.ts

View workflow job for this annotation

GitHub Actions / Release

'z' is defined but never used

const normalizeZodMessage = (error: unknown): string => {
return (error as ZodError).issues
Expand All @@ -20,12 +23,14 @@ const normalizeZodMessage = (error: unknown): string => {
.join('\n');
};

export const getValidatedProjectConfig = (config: unknown): ProjectConfig => {
export const getValidatedProjectConfig = (
config: unknown,
): ProjectConfigOutput => {
return projectConfigSchema.parse(config);
};

export interface ProjectConfigData {
config: ProjectConfig | Record<string, never>;
config: ProjectConfigOutput | Record<string, never>;
filepath: string;
isEmpty?: boolean;
}
Expand Down
10 changes: 10 additions & 0 deletions packages/data-project/src/get-workspace-globs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import fs from 'fs-extra';
import { PackageJson } from '@commonalityco/types';
import yaml from 'yaml';
import { PackageManager } from '@commonalityco/utils-core';
import { getProjectConfig } from './get-project-config';

const defaultWorkspaceGlobs = ['./**'];

Expand All @@ -13,6 +14,15 @@ export const getWorkspaceGlobs = async ({
rootDirectory: string;
packageManager: PackageManager;
}): Promise<string[]> => {
const projectConfig = await getProjectConfig({ rootDirectory });

if (
projectConfig?.config.workspaces &&
projectConfig.config.workspaces.length > 0
) {
return projectConfig.config.workspaces;
}

if (
packageManager === PackageManager.NPM ||
packageManager === PackageManager.BUN ||
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { defineConfig } from 'commonality';

export default defineConfig({});
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { defineConfig } from 'commonality';

export default defineConfig({
workspaces: [],
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { defineConfig } from 'commonality';

export default defineConfig({
workspaces: ['apps/**', 'packages/**'],
});
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"workspaces": [
"./packages/**",
"./apps/**"
"apps/**",
"packages/**"
]
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
packages:
- './packages/**'
- './apps/**'
- 'apps/**'
- 'packages/**'
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"workspaces": [
"./packages/**",
"./apps/**"
"apps/**",
"packages/**"
]
}
16 changes: 16 additions & 0 deletions packages/data-project/test/get-project-config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,19 @@ import { describe, expect, it, test } from 'vitest';
import { fileURLToPath } from 'node:url';

describe('getValidatedProjectConfig', () => {
test('defaults missing properties', () => {
const config = getValidatedProjectConfig({});

expect(config).toEqual({
workspaces: [],
checks: {},
constraints: {},
});
});

test('strips out invalid properties', () => {
const config = getValidatedProjectConfig({
workspacees: 1,
checks: {
'*': [
{
Expand Down Expand Up @@ -41,13 +52,15 @@ describe('getValidatedProjectConfig', () => {
});

expect(config).toEqual({
workspaces: [],
checks: {
'*': [
{
name: 'foo',
validate: expect.any(Function),
fix: expect.any(Function),
message: 'foo',
level: 'warning',
},
],
},
Expand Down Expand Up @@ -86,6 +99,8 @@ describe('getProjectConfig', () => {
});
});

it('returns defaults when the configuration file is empty', () => {});

describe('when run in an initialized project', () => {
it('should return the parsed project config if the file exists and is valid', async () => {
const rootDirectory = path.join(
Expand All @@ -100,6 +115,7 @@ describe('getProjectConfig', () => {
isEmpty: false,
filepath: expect.stringContaining('commonality.config.ts'),
config: {
workspaces: [],
checks: {},
constraints: {
'*': {
Expand Down
157 changes: 83 additions & 74 deletions packages/data-project/test/get-workspace-globs.test.ts
Original file line number Diff line number Diff line change
@@ -1,88 +1,97 @@
import { PackageManager } from '@commonalityco/utils-core';
import path from 'node:path';
import { getWorkspaceGlobs } from '../src/get-workspace-globs';
import { describe, expect, it } from 'vitest';
import { describe, expect, test } from 'vitest';
import { fileURLToPath } from 'node:url';

describe('getWorkspaceGlobs', () => {
describe('when run in an un-initialized project', () => {
it('returns the default globs', async () => {
const rootDirectory = path.join(
path.dirname(fileURLToPath(import.meta.url)),
'./fixtures',
'uninitialized',
);

const config = await getWorkspaceGlobs({
rootDirectory,
packageManager: PackageManager.PNPM,
});

expect(config).toEqual(['./**']);
test('returns default globs when there is no package manager workspaces or explicit workspaces configured', async () => {
const rootDirectory = path.join(
path.dirname(fileURLToPath(import.meta.url)),
'./fixtures',
'uninitialized',
);

const config = await getWorkspaceGlobs({
rootDirectory,
packageManager: PackageManager.NPM,
});

expect(config).toEqual(['./**']);
});

test('returns the workspaces when set via project configuration', async () => {
const rootDirectory = path.join(
path.dirname(fileURLToPath(import.meta.url)),
'./fixtures',
'explicit-workspaces',
);

const workspaceGlobs = await getWorkspaceGlobs({
rootDirectory,
packageManager: PackageManager.PNPM,
});

expect(workspaceGlobs).toEqual(['apps/**', 'packages/**']);
});

test('returns the default globs when set to an empty array via project configuration', async () => {
const rootDirectory = path.join(
path.dirname(fileURLToPath(import.meta.url)),
'./fixtures',
'empty-workspaces',
);

const workspaceGlobs = await getWorkspaceGlobs({
rootDirectory,
packageManager: PackageManager.PNPM,
});

expect(workspaceGlobs).toEqual(['./**']);
});

describe('when run in an initialized project', () => {
describe('when the workspace option exists', () => {
const expectedWorkspaceGlobs = ['./packages/**', './apps/**'];

it(`should return the correct globs for an NPM workspace`, async () => {
const rootDirectory = path.join(
path.dirname(fileURLToPath(import.meta.url)),
'./fixtures',
'npm-workspace',
);
const workspaceGlobs = await getWorkspaceGlobs({
rootDirectory,
packageManager: PackageManager.NPM,
});

expect(workspaceGlobs).toEqual(expectedWorkspaceGlobs);
});

it(`should return the correct globs for a Yarn workspace`, async () => {
const rootDirectory = path.join(
path.dirname(fileURLToPath(import.meta.url)),
'./fixtures',
'yarn-workspace',
);
const workspaceGlobs = await getWorkspaceGlobs({
rootDirectory,
packageManager: PackageManager.YARN,
});

expect(workspaceGlobs).toEqual(expectedWorkspaceGlobs);
});

it(`should return the correct globs for a pnpm workspace`, async () => {
const rootDirectory = path.join(
path.dirname(fileURLToPath(import.meta.url)),
'./fixtures',
'pnpm-workspace',
);
const workspaceGlobs = await getWorkspaceGlobs({
rootDirectory,
packageManager: PackageManager.PNPM,
});

expect(workspaceGlobs).toEqual(expectedWorkspaceGlobs);
});
test('returns the workspaces when set with npm', async () => {
const rootDirectory = path.join(
path.dirname(fileURLToPath(import.meta.url)),
'./fixtures',
'npm-workspace',
);

const workspaceGlobs = await getWorkspaceGlobs({
rootDirectory,
packageManager: PackageManager.NPM,
});

describe('when the workspace option does not exist', () => {
it(`should return the default globs`, async () => {
const rootDirectory = path.join(
path.dirname(fileURLToPath(import.meta.url)),
'./fixtures',
'missing-workspace-globs',
);
const workspaceGlobs = await getWorkspaceGlobs({
rootDirectory,
packageManager: PackageManager.PNPM,
});

expect(workspaceGlobs).toEqual(['./**']);
});
expect(workspaceGlobs).toEqual(['apps/**', 'packages/**']);
});

test('returns the workspaces when set with yarn', async () => {
const rootDirectory = path.join(
path.dirname(fileURLToPath(import.meta.url)),
'./fixtures',
'yarn-workspace',
);

const workspaceGlobs = await getWorkspaceGlobs({
rootDirectory,
packageManager: PackageManager.YARN,
});

expect(workspaceGlobs).toEqual(['apps/**', 'packages/**']);
});

test('returns the workspaces when set with pnpm', async () => {
const rootDirectory = path.join(
path.dirname(fileURLToPath(import.meta.url)),
'./fixtures',
'pnpm-workspace',
);

const workspaceGlobs = await getWorkspaceGlobs({
rootDirectory,
packageManager: PackageManager.PNPM,
});

expect(workspaceGlobs).toEqual(['apps/**', 'packages/**']);
});
});
4 changes: 2 additions & 2 deletions packages/ui-constraints/src/feature-graph-chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import FeatureGraphToolbar from './feature-graph-toolbar';
import { cn } from '@commonalityco/ui-design-system/cn';
import debounce from 'lodash-es/debounce';
import { getElementDefinitions } from '@commonalityco/ui-graph';
import { ProjectConfig } from '@commonalityco/utils-core';
import { ProjectConfigOutput } from '@commonalityco/utils-core';

interface GraphProperties {
packages: Package[];
results: ConstraintResult[];
constraints: ProjectConfig['constraints'];
constraints: ProjectConfigOutput['constraints'];
dependencies: Dependency[];
theme?: string;
onPackageClick: (packageName: string) => void;
Expand Down
Loading

0 comments on commit 0508b8f

Please sign in to comment.