From 82a46e979d77d8b036fff38215df6084279b0c7c Mon Sep 17 00:00:00 2001 From: aramissennyeydd Date: Thu, 8 May 2025 11:18:02 -0400 Subject: [PATCH] start addressing pr feedback Signed-off-by: aramissennyeydd --- packages/repo-tools/package.json | 3 +- .../src/commands/package-docs/Cache.test.ts | 37 +++++++++++++++ .../src/commands/package-docs/Cache.ts | 47 +++++++++++-------- yarn.lock | 7 +-- 4 files changed, 71 insertions(+), 23 deletions(-) create mode 100644 packages/repo-tools/src/commands/package-docs/Cache.test.ts diff --git a/packages/repo-tools/package.json b/packages/repo-tools/package.json index 1963a56f45..4c9806dfc6 100644 --- a/packages/repo-tools/package.json +++ b/packages/repo-tools/package.json @@ -82,7 +82,8 @@ "portfinder": "^1.0.32", "tar": "^6.1.12", "ts-morph": "^24.0.0", - "yaml-diff-patch": "^2.0.0" + "yaml-diff-patch": "^2.0.0", + "zod": "^3.22.4" }, "devDependencies": { "@backstage/backend-test-utils": "workspace:^", diff --git a/packages/repo-tools/src/commands/package-docs/Cache.test.ts b/packages/repo-tools/src/commands/package-docs/Cache.test.ts new file mode 100644 index 0000000000..15205846f3 --- /dev/null +++ b/packages/repo-tools/src/commands/package-docs/Cache.test.ts @@ -0,0 +1,37 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Lockfile } from '@backstage/cli-node'; +import { PackageDocsCache } from './Cache'; +import { join as joinPath } from 'path'; +import { + createMockDirectory, + MockDirectory, +} from '@backstage/backend-test-utils'; + +describe('PackageDocsCache', () => { + let testDir: MockDirectory; + beforeEach(async () => { + testDir = createMockDirectory(); + }); + it('should be able to parse cache files', async () => { + const cache = await PackageDocsCache.loadAsync( + joinPath(__dirname, 'test-cache'), + new Lockfile(), + ); + cache.add('test', 'test'); + }); +}); diff --git a/packages/repo-tools/src/commands/package-docs/Cache.ts b/packages/repo-tools/src/commands/package-docs/Cache.ts index 4cb0b87288..6b64b523e3 100644 --- a/packages/repo-tools/src/commands/package-docs/Cache.ts +++ b/packages/repo-tools/src/commands/package-docs/Cache.ts @@ -15,11 +15,12 @@ */ import { readFile, writeFile, cp } from 'fs/promises'; import globby from 'globby'; -import workerPath, { dirname } from 'path'; +import { dirname, join as joinPath, relative } from 'path'; import crypto from 'crypto'; import { Lockfile } from '@backstage/cli-node'; import { paths as cliPaths } from '../../lib/paths'; import { mkdirp } from 'fs-extra'; +import { z } from 'zod'; const version = '1'; const CACHE_FILE = 'cache.json'; @@ -31,10 +32,19 @@ interface CacheEntry { version: string; } +const cacheEntrySchema = z.object({ + hash: z.string(), + packageName: z.string(), + restoreTo: z.string(), + version: z.string(), +}); + export class PackageDocsCache { + // A map of package directory to package hash. private keyCache: Map; constructor( private readonly lockfile: Lockfile, + // A map of package directory to cache entry. private readonly cache: Map, private readonly cacheDir: string, ) { @@ -47,16 +57,21 @@ export class PackageDocsCache { const map = new Map(); for (const file of cacheFiles) { const pkg = dirname(file); - const cache = await readFile(workerPath.join(cacheDir, file), 'utf-8'); - const cacheJson = JSON.parse(cache); - map.set(pkg, cacheJson); + const cache = await readFile(joinPath(cacheDir, file), 'utf-8'); + try { + const cacheJson = JSON.parse(cache); + const parsed = cacheEntrySchema.parse(cacheJson); + map.set(pkg, parsed); + } catch (e) { + console.error(`Skipping unparseable cache file ${file}: ${e}`); + } } return new PackageDocsCache(lockfile, map, cacheDir); } async directoryToName(directory: string) { const packageJson = await readFile( - workerPath.join(directory, 'package.json'), + joinPath(directory, 'package.json'), 'utf-8', ); return JSON.parse(packageJson).name; @@ -79,7 +94,7 @@ export class PackageDocsCache { for (const path of result.sort()) { const absPath = cliPaths.resolveTargetRoot(pkg, path); - const pathInPackage = workerPath.join(absPath, path); + const pathInPackage = joinPath(absPath, path); hash.update(pathInPackage); hash.update('\0'); hash.update(await readFile(absPath)); @@ -107,8 +122,8 @@ export class PackageDocsCache { } const cacheEntry = this.cache.get(pkg); const restoreTo = cacheEntry!.restoreTo; - const cacheDir = workerPath.join(this.cacheDir, pkg); - const contentsDir = workerPath.join(cacheDir, 'contents'); + const cacheDir = joinPath(this.cacheDir, pkg); + const contentsDir = joinPath(cacheDir, 'contents'); const targetDir = cliPaths.resolveTargetRoot(restoreTo); await mkdirp(targetDir); @@ -116,23 +131,17 @@ export class PackageDocsCache { } async write(pkg: string, contentDirectory: string) { - const cacheDir = workerPath.join(this.cacheDir, pkg); - const contentsDir = workerPath.join(cacheDir, 'contents'); - await mkdirp(cacheDir); + const cacheDir = joinPath(this.cacheDir, pkg); + const contentsDir = joinPath(cacheDir, 'contents'); + await mkdirp(contentsDir); const hashString = await this.toKey(pkg); await cp(contentDirectory, contentsDir, { recursive: true }); const cacheEntry: CacheEntry = { hash: hashString, packageName: await this.directoryToName(pkg), - restoreTo: workerPath.relative( - cliPaths.resolveTargetRoot(), - contentDirectory, - ), + restoreTo: relative(cliPaths.resolveTargetRoot(), contentDirectory), version, }; - await writeFile( - workerPath.join(cacheDir, CACHE_FILE), - JSON.stringify(cacheEntry), - ); + await writeFile(joinPath(cacheDir, CACHE_FILE), JSON.stringify(cacheEntry)); } } diff --git a/yarn.lock b/yarn.lock index 7c9d7d2c58..254464caa9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8429,6 +8429,7 @@ __metadata: ts-morph: "npm:^24.0.0" typedoc: "npm:^0.27.6" yaml-diff-patch: "npm:^2.0.0" + zod: "npm:^3.22.4" peerDependencies: "@microsoft/api-extractor-model": "*" "@microsoft/tsdoc": "*" @@ -48020,9 +48021,9 @@ __metadata: linkType: hard "zod@npm:^3.22.4": - version: 3.23.8 - resolution: "zod@npm:3.23.8" - checksum: 10/846fd73e1af0def79c19d510ea9e4a795544a67d5b34b7e1c4d0425bf6bfd1c719446d94cdfa1721c1987d891321d61f779e8236fde517dc0e524aa851a6eff1 + version: 3.24.4 + resolution: "zod@npm:3.24.4" + checksum: 10/3d545792fa54bb27ee5dbc34a5709e81f603185fcc94c8204b5d95c20dc4c81d870ff9c51f3884a30ef05cdc601449f4c4df254ac4783f0827b1faed7c1cdb48 languageName: node linkType: hard