diff --git a/src/changelog.ts b/src/changelog.ts index 75f2aa49..e91edb89 100644 --- a/src/changelog.ts +++ b/src/changelog.ts @@ -1,4 +1,5 @@ const pMap = require("p-map"); +const { resolve } = require("path"); import progressBar from "./progress-bar"; import { Configuration } from "./configuration"; @@ -79,16 +80,30 @@ export default class Changelog { } private packageFromPath(path: string): string { - const parts = path.split("/"); - if (parts[0] !== "packages" || parts.length < 3) { + if (this.config.packages.length) { + // use the discovered packages + const absolutePath = resolve(this.config.rootPath, path); + + const foundPackage = this.config.packages.find(p => absolutePath.startsWith(p.path)); + + if (foundPackage) { + return foundPackage.name; + } + return ""; - } + } else { + // if we did not find any packages then default to + const parts = path.split("/"); + if (parts[0] !== "packages" || parts.length < 3) { + return ""; + } - if (parts.length >= 4 && parts[1][0] === "@") { - return `${parts[1]}/${parts[2]}`; - } + if (parts.length >= 4 && parts[1][0] === "@") { + return `${parts[1]}/${parts[2]}`; + } - return parts[1]; + return parts[1]; + } } private getListOfCommits(from: string, to: string): Git.CommitListItem[] { diff --git a/src/configuration.ts b/src/configuration.ts index b54c87b9..8f4ec0e4 100644 --- a/src/configuration.ts +++ b/src/configuration.ts @@ -14,6 +14,7 @@ export interface Configuration { cacheDir?: string; nextVersion: string | undefined; nextVersionFromMetadata?: boolean; + packages: [{ name: string; path: string }] | []; } export interface ConfigLoaderOptions { @@ -26,6 +27,34 @@ export function load(options: ConfigLoaderOptions = {}): Configuration { return fromPath(rootPath, options); } +function getPackages(rootPath: string): [{ name: string; path: string }] | [] { + let packages = []; + + if (fs.existsSync(path.join(rootPath, "package-lock.json"))) { + const result = execa.sync("npm", ["query", ".workspace"], { cwd: rootPath }); + const workspaceQuery = JSON.parse(result.stdout); + + packages = workspaceQuery.map((item: any) => ({ name: item.name, path: item.path })); + } else if (fs.existsSync(path.join(rootPath, "pnpm-lock.yaml"))) { + const result = execa.sync(`pnpm`, ["m", "ls", "--json", "--depth=-1"], { cwd: rootPath }); + const workspaceJson = JSON.parse(result.stdout); + + packages = workspaceJson + .filter((item: any) => item.name && item.path) + .map((item: any) => ({ name: item.name, path: item.path })); + } else if (fs.existsSync(path.join(rootPath, "yarn.lock"))) { + const result = execa.sync(`yarn`, ["--silent", "workspaces", "info", "--json"], { cwd: rootPath }); + const workspaceMap = JSON.parse(result.stdout); + + packages = Object.keys(workspaceMap).map(key => ({ + name: key, + path: path.resolve(rootPath, workspaceMap[key].location), + })); + } + + return packages; +} + export function fromPath(rootPath: string, options: ConfigLoaderOptions = {}): Configuration { // Step 1: load partial config from `package.json` or `lerna.json` let config = fromPackageConfig(rootPath) || fromLernaConfig(rootPath) || {}; @@ -37,6 +66,8 @@ export function fromPath(rootPath: string, options: ConfigLoaderOptions = {}): C // Step 2: fill partial config with defaults let { repo, nextVersion, labels, cacheDir, ignoreCommitters } = config; + const packages = getPackages(rootPath); + if (!repo) { repo = findRepo(rootPath); if (!repo) { @@ -81,6 +112,7 @@ export function fromPath(rootPath: string, options: ConfigLoaderOptions = {}): C labels, ignoreCommitters, cacheDir, + packages, }; }