diff --git a/packages/hasher/package.json b/packages/hasher/package.json index 1b931d923..072a39211 100644 --- a/packages/hasher/package.json +++ b/packages/hasher/package.json @@ -22,6 +22,7 @@ "glob-hasher": "^1.4.2", "graceful-fs": "4.2.11", "micromatch": "4.0.8", + "sanitize-filename": "^1.6.3", "workspace-tools": "0.38.3" }, "devDependencies": { diff --git a/packages/hasher/src/TargetHasher.ts b/packages/hasher/src/TargetHasher.ts index cb3f6b7f0..168182feb 100644 --- a/packages/hasher/src/TargetHasher.ts +++ b/packages/hasher/src/TargetHasher.ts @@ -1,6 +1,7 @@ import type { Target } from "@lage-run/target-graph"; import { hash } from "glob-hasher"; import { globAsync } from "@lage-run/globby"; +import sanitize from "sanitize-filename"; import fs from "fs"; import path from "path"; @@ -230,7 +231,7 @@ export class TargetHasher { writeTargetHashesManifest() { for (const [id, { fileHashes, globalFileHashes }] of Object.entries(this.targetHashesLog)) { - const targetHashesManifestPath = path.join(this.targetHashesDirectory, `${id}.json`); + const targetHashesManifestPath = path.join(this.targetHashesDirectory, `${sanitize(id)}.json`); if (!fs.existsSync(path.dirname(targetHashesManifestPath))) { fs.mkdirSync(path.dirname(targetHashesManifestPath), { recursive: true }); } diff --git a/packages/hasher/src/__tests__/TargetHasher.test.ts b/packages/hasher/src/__tests__/TargetHasher.test.ts index f8411792d..01e0dd090 100644 --- a/packages/hasher/src/__tests__/TargetHasher.test.ts +++ b/packages/hasher/src/__tests__/TargetHasher.test.ts @@ -172,4 +172,15 @@ describe("The main Hasher class", () => { monorepo1.cleanup(); }); + + it("sanitizes target hashes filenames when the target contains special characters", async () => { + const monorepo1 = await setupFixture("monorepo"); + const hasher = new TargetHasher({ root: monorepo1.root, environmentGlob: [] }); + const target = createTarget(monorepo1.root, "package-a", "build:test"); + const hash = await getHash(hasher, target); + + expect(() => hasher.writeTargetHashesManifest()).not.toThrow(); + + monorepo1.cleanup(); + }); }); diff --git a/yarn.lock b/yarn.lock index 48c906d06..3e5e7a91c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1804,6 +1804,7 @@ __metadata: glob-hasher: "npm:^1.4.2" graceful-fs: "npm:4.2.11" micromatch: "npm:4.0.8" + sanitize-filename: "npm:^1.6.3" workspace-tools: "npm:0.38.3" languageName: unknown linkType: soft @@ -7610,6 +7611,15 @@ __metadata: languageName: node linkType: hard +"sanitize-filename@npm:^1.6.3": + version: 1.6.3 + resolution: "sanitize-filename@npm:1.6.3" + dependencies: + truncate-utf8-bytes: "npm:^1.0.0" + checksum: 10c0/16ff47556a6e54e228c28db096bedd303da67b030d4bea4925fd71324932d6b02c7b0446f00ad33987b25b6414f24ae968e01a1a1679ce599542e82c4b07eb1f + languageName: node + linkType: hard + "sax@npm:>=0.6.0": version: 1.2.4 resolution: "sax@npm:1.2.4" @@ -8237,6 +8247,15 @@ __metadata: languageName: node linkType: hard +"truncate-utf8-bytes@npm:^1.0.0": + version: 1.0.2 + resolution: "truncate-utf8-bytes@npm:1.0.2" + dependencies: + utf8-byte-length: "npm:^1.0.1" + checksum: 10c0/af2b431fc4314f119b551e5fccfad49d4c0ef82e13ba9ca61be6567801195b08e732ce9643542e8ad1b3df44f3df2d7345b3dd34f723954b6bb43a14584d6b3c + languageName: node + linkType: hard + "ts-node@npm:^10.9.1": version: 10.9.1 resolution: "ts-node@npm:10.9.1" @@ -8475,6 +8494,13 @@ __metadata: languageName: node linkType: hard +"utf8-byte-length@npm:^1.0.1": + version: 1.0.5 + resolution: "utf8-byte-length@npm:1.0.5" + checksum: 10c0/e69bda3299608f4cc75976da9fb74ac94801a58b9ca29fdad03a20ec952e7477d7f226c12716b5f36bd4cff8151d1d152d02ee1df3752f017d4b2c725ce3e47a + languageName: node + linkType: hard + "util-deprecate@npm:^1.0.1": version: 1.0.2 resolution: "util-deprecate@npm:1.0.2"