From 27720fb9694e6a645d99dccd000227db04089555 Mon Sep 17 00:00:00 2001 From: Elizabeth Craig Date: Thu, 29 Jul 2021 23:32:48 -0700 Subject: [PATCH] Add caching of changed packages --- ...-1cc40d1b-98c5-48b9-8387-c6a7f1dbf6a1.json | 7 +++ src/__e2e__/multiMonorepo.test.ts | 3 +- src/changefile/getChangedPackages.ts | 62 ++++++++++++------- 3 files changed, 48 insertions(+), 24 deletions(-) create mode 100644 change/beachball-1cc40d1b-98c5-48b9-8387-c6a7f1dbf6a1.json diff --git a/change/beachball-1cc40d1b-98c5-48b9-8387-c6a7f1dbf6a1.json b/change/beachball-1cc40d1b-98c5-48b9-8387-c6a7f1dbf6a1.json new file mode 100644 index 000000000..95dd6a84d --- /dev/null +++ b/change/beachball-1cc40d1b-98c5-48b9-8387-c6a7f1dbf6a1.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "Add caching of changed packages", + "packageName": "beachball", + "email": "elcraig@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/src/__e2e__/multiMonorepo.test.ts b/src/__e2e__/multiMonorepo.test.ts index 089ea3cc4..681ccf040 100644 --- a/src/__e2e__/multiMonorepo.test.ts +++ b/src/__e2e__/multiMonorepo.test.ts @@ -1,7 +1,7 @@ import fs from 'fs-extra'; import path from 'path'; import { RepositoryFactory } from '../fixtures/repository'; -import { getChangedPackages } from '../changefile/getChangedPackages'; +import { getChangedPackages, resetChangedPackagesCache } from '../changefile/getChangedPackages'; import { writeChangeFiles } from '../changefile/writeChangeFiles'; import { git } from 'workspace-tools'; import { bump } from '../commands/bump'; @@ -14,6 +14,7 @@ describe('changed files', () => { let repositoryFactory: RepositoryFactory | undefined; afterEach(() => { + resetChangedPackagesCache(); if (repositoryFactory) { repositoryFactory.cleanUp(); repositoryFactory = undefined; diff --git a/src/changefile/getChangedPackages.ts b/src/changefile/getChangedPackages.ts index d6488109a..e311eca1a 100644 --- a/src/changefile/getChangedPackages.ts +++ b/src/changefile/getChangedPackages.ts @@ -7,6 +7,17 @@ import { getScopedPackages } from '../monorepo/getScopedPackages'; import { BeachballOptions } from '../types/BeachballOptions'; import { PackageInfos } from '../types/PackageInfo'; +let cachedPackages: { [key: string]: ReadonlyArray } = {}; + +function getCacheKey(options: BeachballOptions) { + return [options.path, options.branch, options.fetch].join('-'); +} + +/** Reset the cache for `getChangedPackages` */ +export function resetChangedPackagesCache() { + cachedPackages = {}; +} + /** * Gets all the changed packages, regardless of the change files */ @@ -17,30 +28,28 @@ function getAllChangedPackages(options: BeachballOptions, packageInfos: PackageI const scopedPackages = getScopedPackages(options, packageInfos); const ignoredFiles = ['CHANGELOG.md', 'CHANGELOG.json']; const packageRoots: { [pathName: string]: string } = {}; - if (changes) { - // Discover package roots from modded files (ignores the CHANGELOG file because that's generated by beachball) - changes - .filter(name => !ignoredFiles.includes(path.basename(name))) - .forEach(moddedFile => { - const root = findPackageRoot(path.join(cwd, path.dirname(moddedFile))); - - if (root && !packageRoots[root]) { - try { - const packageJson = fs.readJSONSync(path.join(root, 'package.json')); - - if (!packageJson.private && (!packageJson.beachball || packageJson.beachball.shouldPublish !== false)) { - const packageName = packageJson.name; - - if (scopedPackages.includes(packageName)) { - packageRoots[root] = packageName; - } + // Discover package roots from modded files (ignores the CHANGELOG file because that's generated by beachball) + changes + .filter(name => !ignoredFiles.includes(path.basename(name))) + .forEach(moddedFile => { + const root = findPackageRoot(path.join(cwd, path.dirname(moddedFile))); + + if (root && !packageRoots[root]) { + try { + const packageJson = fs.readJSONSync(path.join(root, 'package.json')); + + if (!packageJson.private && (!packageJson.beachball || packageJson.beachball.shouldPublish !== false)) { + const packageName = packageJson.name; + + if (scopedPackages.includes(packageName)) { + packageRoots[root] = packageName; } - } catch (e) { - // Ignore JSON errors } + } catch (e) { + // Ignore JSON errors } - }); - } + } + }); return Object.values(packageRoots); } @@ -50,6 +59,11 @@ function getAllChangedPackages(options: BeachballOptions, packageInfos: PackageI */ export function getChangedPackages(options: BeachballOptions, packageInfos: PackageInfos) { const { fetch, path: cwd, branch } = options; + const cacheKey = getCacheKey(options); + + if (cachedPackages[cacheKey]) { + return cachedPackages[cacheKey]; + } const changePath = getChangePath(cwd); @@ -59,7 +73,7 @@ export function getChangedPackages(options: BeachballOptions, packageInfos: Pack fetchRemoteBranch(remote, remoteBranch, cwd); } - const changedPackages = getAllChangedPackages(options, packageInfos); + let changedPackages = getAllChangedPackages(options, packageInfos); const changeFilesResult = git( ['diff', '--name-only', '--relative', '--no-renames', '--diff-filter=A', `${branch}...`], @@ -67,6 +81,7 @@ export function getChangedPackages(options: BeachballOptions, packageInfos: Pack ); if (!changePath || !fs.existsSync(changePath) || !changeFilesResult.success) { + cachedPackages[cacheKey] = changedPackages; return changedPackages; } @@ -94,5 +109,6 @@ export function getChangedPackages(options: BeachballOptions, packageInfos: Pack ); } - return changedPackages.filter(pkgName => !changeFilePackageSet.has(pkgName)); + changedPackages = cachedPackages[cacheKey] = changedPackages.filter(pkgName => !changeFilePackageSet.has(pkgName)); + return changedPackages; }