Skip to content

Commit

Permalink
Adapt implementation and tests to new interface
Browse files Browse the repository at this point in the history
  • Loading branch information
Cristiano Belloni committed Aug 9, 2022
1 parent 02291ec commit 9993454
Show file tree
Hide file tree
Showing 3 changed files with 247 additions and 73 deletions.
Original file line number Diff line number Diff line change
@@ -1,24 +1,73 @@
import { matchWorkspaces } from '../../utils/getChangedWorkspaces';
import type { WorkspaceContent } from '../../utils/getAllWorkspaces';

describe('matchWorkspaces', () => {
it('matches absolute manifests paths with holes and duplication to subset of workspace entries', () => {
const workspaces = {
'workspace-1': {
location: 'packages/workspace-1',
workspaceDependencies: ['workspace-2', 'workspace-3'],
mismatchedWorkspaceDependencies: [],
},
'workspace-2': {
location: 'packages/workspace-2',
workspaceDependencies: ['workspace-3'],
mismatchedWorkspaceDependencies: [],
},
'workspace-3': {
location: 'packages/workspace-3',
workspaceDependencies: [],
mismatchedWorkspaceDependencies: [],
const workspacesContent: WorkspaceContent = [
new Map(
Object.entries({
'workspace-1': {
path: 'w1',
location: 'w1',
name: 'workspace-1',
version: '0.0.1',
workspace: false,
modular: {
type: 'package',
},
children: [],
parent: null,
dependencies: undefined,
rawPackageJson: {},
},
'workspace-2': {
path: 'w2',
location: '/w2',
name: 'workspace-3',
version: '0.0.1',
workspace: false,
modular: {
type: 'package',
},
children: [],
parent: null,
dependencies: undefined,
rawPackageJson: {},
},
'workspace-3': {
path: 'w3',
location: '/w3',
name: 'workspace-3',
version: '0.0.1',
workspace: false,
modular: {
type: 'package',
},
children: [],
parent: null,
dependencies: undefined,
rawPackageJson: {},
},
}),
),
{
'workspace-1': {
location: 'packages/workspace-1',
workspaceDependencies: ['workspace-2', 'workspace-3'],
mismatchedWorkspaceDependencies: [],
},
'workspace-2': {
location: 'packages/workspace-2',
workspaceDependencies: ['workspace-3'],
mismatchedWorkspaceDependencies: [],
},
'workspace-3': {
location: 'packages/workspace-3',
workspaceDependencies: [],
mismatchedWorkspaceDependencies: [],
},
},
};
];

const listOfPackageManifests = [
'/my/path/packages/workspace-1/package.json',
Expand All @@ -28,62 +77,178 @@ describe('matchWorkspaces', () => {
];

expect(
matchWorkspaces(listOfPackageManifests, '/my/path', workspaces),
).toEqual({
'workspace-1': {
location: 'packages/workspace-1',
workspaceDependencies: ['workspace-2', 'workspace-3'],
mismatchedWorkspaceDependencies: [],
},
'workspace-3': {
location: 'packages/workspace-3',
workspaceDependencies: [],
mismatchedWorkspaceDependencies: [],
matchWorkspaces(listOfPackageManifests, '/my/path', workspacesContent),
).toEqual([
new Map(
Object.entries({
'workspace-1': {
path: 'w1',
location: 'w1',
name: 'workspace-1',
version: '0.0.1',
workspace: false,
modular: {
type: 'package',
},
children: [],
parent: null,
dependencies: undefined,
rawPackageJson: {},
},
'workspace-3': {
path: 'w3',
location: '/w3',
name: 'workspace-3',
version: '0.0.1',
workspace: false,
modular: {
type: 'package',
},
children: [],
parent: null,
dependencies: undefined,
rawPackageJson: {},
},
}),
),
{
'workspace-1': {
location: 'packages/workspace-1',
workspaceDependencies: ['workspace-2', 'workspace-3'],
mismatchedWorkspaceDependencies: [],
},
'workspace-3': {
location: 'packages/workspace-3',
workspaceDependencies: [],
mismatchedWorkspaceDependencies: [],
},
},
});
]);
});

it('does not match paths outside of known workspaces', () => {
const workspaces = {
'workspace-1': {
location: 'packages/workspace-1',
workspaceDependencies: ['workspace-2', 'workspace-3'],
mismatchedWorkspaceDependencies: [],
},
'workspace-2': {
location: 'packages/workspace-2',
workspaceDependencies: ['workspace-3'],
mismatchedWorkspaceDependencies: [],
},
'workspace-3': {
location: 'packages/workspace-3',
workspaceDependencies: [],
mismatchedWorkspaceDependencies: [],
const workspacesContent: WorkspaceContent = [
new Map(
Object.entries({
'workspace-1': {
path: 'w1',
location: 'w1',
name: 'workspace-1',
version: '0.0.1',
workspace: false,
modular: {
type: 'package',
},
children: [],
parent: null,
dependencies: undefined,
rawPackageJson: {},
},
'workspace-2': {
path: 'w2',
location: '/w2',
name: 'workspace-3',
version: '0.0.1',
workspace: false,
modular: {
type: 'package',
},
children: [],
parent: null,
dependencies: undefined,
rawPackageJson: {},
},
'workspace-3': {
path: 'w3',
location: '/w3',
name: 'workspace-3',
version: '0.0.1',
workspace: false,
modular: {
type: 'package',
},
children: [],
parent: null,
dependencies: undefined,
rawPackageJson: {},
},
}),
),
{
'workspace-1': {
location: 'packages/workspace-1',
workspaceDependencies: ['workspace-2', 'workspace-3'],
mismatchedWorkspaceDependencies: [],
},
'workspace-2': {
location: 'packages/workspace-2',
workspaceDependencies: ['workspace-3'],
mismatchedWorkspaceDependencies: [],
},
'workspace-3': {
location: 'packages/workspace-3',
workspaceDependencies: [],
mismatchedWorkspaceDependencies: [],
},
},
};
];

const listOfPackageManifests = [
'/my/path/packages/workspace-nope/package.json',
];

expect(
matchWorkspaces(listOfPackageManifests, '/my/path', workspaces),
).toEqual({});
matchWorkspaces(listOfPackageManifests, '/my/path', workspacesContent),
).toEqual([new Map([]), {}]);
});

it('works with a root workspace', () => {
const workspaces = {
'workspace-root': {
location: '',
workspaceDependencies: [],
mismatchedWorkspaceDependencies: [],
},
'workspace-non-root': {
location: 'packages/workspace-non-root',
workspaceDependencies: [],
mismatchedWorkspaceDependencies: [],
const workspacesContent: WorkspaceContent = [
new Map(
Object.entries({
'workspace-root': {
path: 'w1',
location: 'w1',
name: 'workspace-1',
version: '0.0.1',
workspace: true,
modular: {
type: 'root',
},
children: [],
parent: null,
dependencies: undefined,
rawPackageJson: {},
},
'workspace-non-root': {
path: 'workspace-non-root',
location: '/workspace-non-root',
name: 'workspace-non-root',
version: '0.0.1',
workspace: false,
modular: {
type: 'package',
},
children: [],
parent: null,
dependencies: undefined,
rawPackageJson: {},
},
}),
),
{
'workspace-root': {
location: '',
workspaceDependencies: [],
mismatchedWorkspaceDependencies: [],
},
'workspace-non-root': {
location: 'packages/workspace-non-root',
workspaceDependencies: [],
mismatchedWorkspaceDependencies: [],
},
},
};
];

const listOfPackageManifests = [
'/my/path/workspace-root/package.json',
Expand All @@ -94,8 +259,8 @@ describe('matchWorkspaces', () => {
matchWorkspaces(
listOfPackageManifests,
'/my/path/workspace-root',
workspaces,
workspacesContent,
),
).toEqual(workspaces);
).toEqual(workspacesContent);
});
});
5 changes: 4 additions & 1 deletion packages/modular-scripts/src/utils/getAllWorkspaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ import type {
ModularWorkspacePackage,
} from '@modular-scripts/modular-types';

type WorkspaceContent = [Map<string, ModularWorkspacePackage>, WorkspaceMap];
export type WorkspaceContent = [
Map<string, ModularWorkspacePackage>,
WorkspaceMap,
];
export interface PackageManagerInfo {
getWorkspaceCommand: string;
formatWorkspaceCommandOutput: (stdout: string) => WorkspaceMap;
Expand Down
32 changes: 19 additions & 13 deletions packages/modular-scripts/src/utils/getChangedWorkspaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,46 +3,52 @@ import pkgUp from 'pkg-up';
import { getDiffedFiles } from './gitActions';
import { getAllWorkspaces } from './getAllWorkspaces';
import getModularRoot from './getModularRoot';
import { WorkspaceMap } from '@modular-scripts/modular-types';
import type { WorkspaceContent } from './getAllWorkspaces';

// Gets a list of changed files, then maps them to their workspace and returns a subset of WorkspaceMap
// Gets a list of changed files, then maps them to their workspace and returns a subset of WorkspaceContent
export async function getChangedWorkspaces(
targetBranch: string,
): Promise<WorkspaceMap> {
): Promise<WorkspaceContent> {
const diffedFiles = getDiffedFiles(targetBranch);
const workspaces = await getAllWorkspaces();
const workspaceContent = await getAllWorkspaces();
const modularRoot = getModularRoot();

// Resolve each of the changed files to their nearest package.json. The resulting list can contain duplicates and null holes
const packageManifestPaths = await Promise.all(
diffedFiles.map((changedFile) => pkgUp({ cwd: path.dirname(changedFile) })),
);

return matchWorkspaces(packageManifestPaths, modularRoot, workspaces);
return matchWorkspaces(packageManifestPaths, modularRoot, workspaceContent);
}

// Match workspace manifest paths to a subset of WorkspaceMap. This function works completely in memory and is test-friendly
// Match workspace manifest paths to a subset of WorkspaceContent. This function works completely in memory and is test-friendly
export function matchWorkspaces(
packagePaths: (string | null)[],
root: string,
workspaces: WorkspaceMap,
): WorkspaceMap {
workspaceContent: WorkspaceContent,
): WorkspaceContent {
const [packages, workspaces] = workspaceContent;
const workspaceEntries = Object.entries(workspaces);
const result: WorkspaceMap = {};
const result: WorkspaceContent = [new Map([]), {}];

for (const packagePath of packagePaths) {
const [resultPackages, resultWorkspaces] = result;
// Ignore holes
if (!packagePath) continue;
// Get the package directory from the package.json path and make it relative to the root, for comparison with the original WorkspaceMap
// Get the package directory from the package.json path and make it relative to the root, for comparison with the original WorkspaceContent
const packageDir = path.relative(root, path.dirname(packagePath));
// Match the package directory to its entry WorkspaceMap, using pathEquality
// Match the package directory to its entry WorkspaceContent, using pathEquality
const foundEntry = workspaceEntries.find(([_, { location }]) =>
pathEquality(location, packageDir),
);
// If found, insert the entry into the WorkspaceMap that we are building
// If found, insert the entries into the WorkspaceContent that we are building
if (foundEntry) {
const [foundWorkspaceName, foundWorkspace] = foundEntry;
result[foundWorkspaceName] = foundWorkspace;
resultWorkspaces[foundWorkspaceName] = foundWorkspace;
const foundPackage = packages.get(foundWorkspaceName);
if (foundPackage) {
resultPackages.set(foundWorkspaceName, foundPackage);
}
}
}
return result;
Expand Down

0 comments on commit 9993454

Please sign in to comment.