Skip to content

Commit

Permalink
feat: add lerna at the root of a new otter project (#1956)
Browse files Browse the repository at this point in the history
## Proposed change

The goal is to add lerna at the root when creating an Otter project so
that we can easily run the commands for all projects locally and on the
CI with both npm and yarn.
  • Loading branch information
vscaiceanu-1a committed Jul 24, 2024
2 parents 74873ad + feeadcb commit 8765cf4
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 8 deletions.
3 changes: 2 additions & 1 deletion packages/@o3r/workspace/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,8 @@
"@angular/material": "~18.0.0",
"@ngrx/router-store": "~18.0.0",
"@ngrx/effects": "~18.0.0",
"@ngrx/store-devtools": "~18.0.0"
"@ngrx/store-devtools": "~18.0.0",
"lerna": "^8.1.7"
},
"engines": {
"node": "^18.19.1 || ^20.11.1 || >=22.0.0"
Expand Down
21 changes: 20 additions & 1 deletion packages/@o3r/workspace/schematics/index.it.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ import {
getDefaultExecSyncOptions, getGitDiff,
packageManagerExec,
packageManagerInstall,
packageManagerRun,
packageManagerRunOnProject
} from '@o3r/test-helpers';
import { existsSync } from 'node:fs';
import { existsSync, promises as fs } from 'node:fs';
import * as path from 'node:path';
import type { PackageJson } from 'type-fest';

describe('new otter workspace', () => {
test('should add sdk to an existing workspace', () => {
Expand Down Expand Up @@ -78,4 +80,21 @@ describe('new otter workspace', () => {
generatedLibFiles.forEach(file => expect(existsSync(path.join(inLibraryPath, file))).toBe(true));
expect(() => packageManagerRunOnProject(libName, true, { script: 'build' }, execAppOptions)).not.toThrow();
});

test('should generate a monorepo setup', async () => {
const { workspacePath } = o3rEnvironment.testEnvironment;
const defaultOptions = getDefaultExecSyncOptions();
// eslint-disable-next-line @typescript-eslint/naming-convention
const execAppOptions = {...defaultOptions, cwd: workspacePath, env: {...defaultOptions.env, NX_CLOUD_ACCESS_TOKEN: ''}};
expect(() => packageManagerInstall(execAppOptions)).not.toThrow();
const rootPackageJson = JSON.parse(await fs.readFile(path.join(workspacePath, 'package.json'), 'utf-8')) as PackageJson;
expect(rootPackageJson.scripts).toHaveProperty('build', 'lerna run build');
expect(rootPackageJson.scripts).toHaveProperty('test', 'lerna run test');
expect(rootPackageJson.scripts).toHaveProperty('lint', 'lerna run lint');
expect(() => packageManagerRun({script: 'build'}, execAppOptions)).not.toThrow();
expect(() => packageManagerRun({script: 'test'}, execAppOptions)).not.toThrow();
expect(() => packageManagerRun({script: 'lint'}, execAppOptions)).not.toThrow();
expect(rootPackageJson.workspaces).toContain('libs/*');
expect(rootPackageJson.workspaces).toContain('apps/*');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { chain } from '@angular-devkit/schematics';
import type { Rule, SchematicContext, Tree } from '@angular-devkit/schematics';
import { SchematicsException } from '@angular-devkit/schematics';
import type { PackageJson } from 'type-fest';
import { DEFAULT_ROOT_FOLDERS, isNxContext, setupSchematicsParamsForProject, WorkspaceLayout, WorkspaceSchematics } from '@o3r/schematics';
import { DEFAULT_ROOT_FOLDERS, getPackageManager, isNxContext, setupSchematicsParamsForProject, WorkspaceLayout, WorkspaceSchematics } from '@o3r/schematics';
import type { MonorepoManager } from '../schema';

/**
* Update root package.json to include workspaces
Expand Down Expand Up @@ -75,3 +76,43 @@ export function filterPackageJsonScripts(tree: Tree, _context: SchematicContext)
tree.overwrite(rootPackageJsonPath, JSON.stringify(rootPackageJsonObject, null, 2));
return tree;
}

/**
* Add a monorepo manager at the root of the project
* @param o3rWorkspacePackageJson the @o3r/workspace package.json
* @param manager the monorepo manager
*/
export function addMonorepoManager(o3rWorkspacePackageJson: PackageJson & { generatorDependencies: Record<string, string> }, manager: MonorepoManager): Rule {
return (tree: Tree, _context: SchematicContext) => {
if (manager === 'lerna') {
const rootPackageJsonPath = '/package.json';
if (!tree.exists(rootPackageJsonPath)) {
throw new SchematicsException('Root package.json does not exist');
}

const rootPackageJsonObject = tree.readJson(rootPackageJsonPath) as PackageJson;
rootPackageJsonObject.devDependencies = {
...rootPackageJsonObject.devDependencies,
'lerna': o3rWorkspacePackageJson.generatorDependencies.lerna
};
rootPackageJsonObject.scripts = {
...rootPackageJsonObject.scripts,
'build': 'lerna run build',
'test': 'lerna run test',
'lint': 'lerna run lint'
};

const lernaJson: { $schema: string; version: string; npmClient?: string } = {
'$schema': 'https://github.com/lerna/lerna/blob/main/packages/lerna/schemas/lerna-schema.json',
'version': rootPackageJsonObject.version || '0.0.0-placeholder'
};
if (getPackageManager() === 'yarn') {
lernaJson.npmClient = 'yarn';
}
tree.create('/lerna.json', JSON.stringify(lernaJson, null, 2));

tree.overwrite(rootPackageJsonPath, JSON.stringify(rootPackageJsonObject, null, 2));
}
return tree;
};
}
8 changes: 5 additions & 3 deletions packages/@o3r/workspace/schematics/ng-add/project-setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ import type { DependencyToAdd } from '@o3r/schematics';
import { NodeDependencyType } from '@schematics/angular/utility/dependencies';
import * as fs from 'node:fs';
import * as path from 'node:path';
import { addWorkspacesToProject, filterPackageJsonScripts } from './helpers/npm-workspace';
import { addMonorepoManager, addWorkspacesToProject, filterPackageJsonScripts } from './helpers/npm-workspace';
import { generateRenovateConfig } from './helpers/renovate';
import type { NgAddSchematicsSchema } from './schema';
import { shouldOtterLinterBeInstalled } from './helpers/linter';
import { updateGitIgnore } from './helpers/gitignore-update';
import type { PackageJson } from 'type-fest';

/**
* Enable all the otter features requested by the user
Expand All @@ -34,7 +35,7 @@ export const prepareProject = (options: NgAddSchematicsSchema): Rule => {
const ownSchematicsFolder = path.resolve(__dirname, '..');
const ownPackageJsonPath = path.resolve(ownSchematicsFolder, '..', 'package.json');
const depsInfo = getO3rPeerDeps(ownPackageJsonPath);
const ownPackageJsonContent = JSON.parse(fs.readFileSync(ownPackageJsonPath, { encoding: 'utf-8' }));
const ownPackageJsonContent = JSON.parse(fs.readFileSync(ownPackageJsonPath, { encoding: 'utf-8' })) as PackageJson & { generatorDependencies: Record<string, string> };

return async (tree, context) => {
if (!ownPackageJsonContent) {
Expand Down Expand Up @@ -74,7 +75,8 @@ export const prepareProject = (options: NgAddSchematicsSchema): Rule => {
ngAddToRun: internalPackagesToInstallWithNgAdd
}),
!options.skipLinter && installOtterLinter ? applyEsLintFix() : noop(),
addWorkspacesToProject()
addWorkspacesToProject(),
addMonorepoManager(ownPackageJsonContent, options.monorepoManager)
])(tree, context);
};
};
9 changes: 9 additions & 0 deletions packages/@o3r/workspace/schematics/ng-add/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,15 @@
"type": "boolean",
"description": "Use a pinned version for otter packages",
"default": false
},
"monorepoManager": {
"description": "Which monorepo manager to use",
"type": "string",
"default": "lerna",
"enum": [
"lerna",
"none"
]
}
},
"additionalProperties": true,
Expand Down
6 changes: 5 additions & 1 deletion packages/@o3r/workspace/schematics/ng-add/schema.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { SchematicOptionObject } from '@o3r/schematics';

export type PresetNames = 'basic' | 'cms';
/** Monorepo manager to use */
export type MonorepoManager = 'lerna' | 'none';

export interface NgAddSchematicsSchema extends SchematicOptionObject {
/** Skip the linter process */
Expand All @@ -17,4 +18,7 @@ export interface NgAddSchematicsSchema extends SchematicOptionObject {

/** Use a pinned version for otter packages */
exactO3rVersion?: boolean;

/** Monorepo manager to use */
monorepoManager: MonorepoManager;
}
2 changes: 1 addition & 1 deletion packages/@o3r/workspace/src/cli/set-version.cts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import * as path from 'node:path';
import * as winston from 'winston';
import { clean } from 'semver';

const defaultIncludedFiles = ['**/package.json', '!/**/templates/**/package.json', '!**/node_modules/**/package.json'];
const defaultIncludedFiles = ['**/package.json', '!/**/templates/**/package.json', '!**/node_modules/**/package.json', '**/lerna.json'];

const collect = (pattern: string, patterns: string[]) => {
if (patterns === defaultIncludedFiles && pattern) {
Expand Down

0 comments on commit 8765cf4

Please sign in to comment.