packages/@aws-cdk-testing/cli-integ/lib/package-sources/repo-source.ts (81 lines of code) (raw):

import * as os from 'os'; import * as path from 'path'; import * as fs from 'fs-extra'; import type { IPackageSourceSetup, IPackageSource } from './source'; import { findUp } from '../files'; import { shell, addToShellPath } from '../shell'; export class RepoPackageSourceSetup implements IPackageSourceSetup { readonly name = 'repo'; readonly description: string; constructor(private readonly repoRoot: string) { this.description = `repo(${this.repoRoot})`; } public async prepare(): Promise<void> { if (!await fs.pathExists(path.join(this.repoRoot, 'package.json')) || !await fs.pathExists(path.join(this.repoRoot, 'yarn.lock'))) { throw new Error(`${this.repoRoot}: does not look like the repository root`); } process.env.REPO_ROOT = this.repoRoot; process.env.REPO_PACKAGE_MAP = await writePackageMap(this.repoRoot); addToShellPath(path.resolve(__dirname, 'repo-tools')); } public async cleanup(): Promise<void> { } } export class RepoPackageSource implements IPackageSource { private readonly repoRoot: string; constructor() { this.repoRoot = process.env.REPO_ROOT as string; } public async makeCliAvailable() { addToShellPath(path.join(this.repoRoot, 'packages', 'aws-cdk', 'bin')); } public assertJsiiPackagesAvailable() { throw new Error('jsii client packages are not available when using REPO source'); } public async initializeDotnetPackages() { } public majorVersion() { const releaseJson = fs.readJsonSync(path.resolve(this.repoRoot, 'release.json')); return releaseJson.majorVersion; } public requestedCliVersion(): string { return '*'; } public requestedFrameworkVersion(): string { return '*'; } public requestedAlphaVersion(): string { return '*'; } } async function writePackageMap(repoRoot: string): Promise<string> { const packages = await findYarnPackages(repoRoot); const fileName = path.join(os.tmpdir(), 'package-map.json'); await fs.writeJson(fileName, packages); return fileName; } /** * Cache monorepo discovery results, we only want to do this once per run */ const YARN_MONOREPO_CACHE: Record<string, any> = {}; /** * Return a { name -> directory } packages found in a Yarn monorepo * * Cached in YARN_MONOREPO_CACHE. */ export async function findYarnPackages(root: string): Promise<Record<string, string>> { if (!(root in YARN_MONOREPO_CACHE)) { const outputDataString: string = JSON.parse(await shell(['yarn', 'workspaces', '--json', 'info'], { captureStderr: false, cwd: root, show: 'error', })).data; const output: YarnWorkspacesOutput = JSON.parse(outputDataString); const ret: Record<string, string> = {}; for (const [k, v] of Object.entries(output)) { ret[k] = path.join(root, v.location); } YARN_MONOREPO_CACHE[root] = ret; } return YARN_MONOREPO_CACHE[root]; } /** * Find the root directory of the repo from the current directory */ export async function autoFindRoot() { const found = findUp('release.json'); if (!found) { throw new Error(`Could not determine repository root: 'release.json' not found from ${process.cwd()}`); } return path.dirname(found); } type YarnWorkspacesOutput = Record<string, { location: string }>;