Skip to content

Commit 6417f78

Browse files
committed
fix: add repository metadata to git package builds
1 parent 15561ff commit 6417f78

3 files changed

Lines changed: 188 additions & 1 deletion

File tree

azure-pipelines.yml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,11 +211,17 @@ stages:
211211
212212
- script: |
213213
set -euo pipefail
214+
REPOSITORY_REVISION=$(git -C "$(repoDir)" rev-parse HEAD)
214215
cd "$(packageFolder)"
216+
echo "Patching repository metadata in $(packageFolder)"
217+
node "$(Build.SourcesDirectory)/patchPackageRepository.js" \
218+
. \
219+
"$(repoUrl)" \
220+
"$REPOSITORY_REVISION"
215221
echo "Overriding publishConfig.registry in $(packageFolder)"
216222
npm pkg set publishConfig.registry="$(publishRegistryUrl)"
217223
cat package.json
218-
displayName: "Override publishConfig"
224+
displayName: "Patch package metadata"
219225
condition: eq(variables['packageSourceMode'], 'git')
220226
221227
- script: |
@@ -470,6 +476,10 @@ stages:
470476
set -euo pipefail
471477
echo "Published package metadata from Verdaccio:"
472478
npm view "$(packageNameFromArtifact)" --registry="$(verdaccioUrl)" --json
479+
if [ "${PACKAGESOURCE:-git}" = "git" ]; then
480+
REPOSITORY_JSON=$(npm view "$(packageNameFromArtifact)@$(packageVersionFromArtifact)" repository --registry="$(verdaccioUrl)" --json)
481+
node -e 'const repo=JSON.parse(process.argv[1]); if (!repo || repo.type !== "git" || typeof repo.url !== "string" || repo.url.length === 0 || typeof repo.revision !== "string" || !/^[0-9a-f]{40}$/.test(repo.revision)) { console.error("Published package repository metadata is invalid"); console.error(JSON.stringify(repo)); process.exit(1); }' "$REPOSITORY_JSON"
482+
fi
473483
echo "Verdaccio storage files:"
474484
find "$(Pipeline.Workspace)/verdaccio-storage" -type f | sort
475485
displayName: "Print Verdaccio registry content"

patchPackageRepository.js

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
const fs = require("fs");
2+
const path = require("path");
3+
const { logError } = require("./lib/logger");
4+
const { readPackageJson } = require("./lib/packageJson");
5+
6+
/**
7+
* @typedef {{type: string, url: string, revision: string}} RepositoryMetadata
8+
*/
9+
10+
/**
11+
* @typedef {{
12+
* [key: string]: unknown,
13+
* name?: string,
14+
* version?: string,
15+
* displayName?: string,
16+
* dependencies?: Record<string, string>,
17+
* repository?: RepositoryMetadata,
18+
* }} PackageManifest
19+
*/
20+
21+
/**
22+
* @param {string} value
23+
* @param {string} name
24+
* @returns {void}
25+
*/
26+
const assertNonEmptyString = function (value, name) {
27+
if (typeof value !== "string" || value.trim() === "") {
28+
throw new Error(`${name} is required`);
29+
}
30+
};
31+
32+
/**
33+
* @param {string} packageFolder
34+
* @param {string} repoUrl
35+
* @param {string} revision
36+
* @returns {PackageManifest & {repository: RepositoryMetadata}}
37+
*/
38+
const patchPackageRepository = function (packageFolder, repoUrl, revision) {
39+
assertNonEmptyString(packageFolder, "packageFolder");
40+
assertNonEmptyString(repoUrl, "repoUrl");
41+
assertNonEmptyString(revision, "revision");
42+
43+
const packageJsonPath = path.resolve(packageFolder, "package.json");
44+
const packageJson = /** @type {PackageManifest} */ (
45+
readPackageJson(packageJsonPath)
46+
);
47+
48+
packageJson.repository = {
49+
type: "git",
50+
url: repoUrl,
51+
revision,
52+
};
53+
54+
fs.writeFileSync(
55+
packageJsonPath,
56+
`${JSON.stringify(packageJson, null, 2)}\n`,
57+
);
58+
59+
return /** @type {PackageManifest & {repository: RepositoryMetadata}} */ (
60+
packageJson
61+
);
62+
};
63+
64+
if (require.main === module) {
65+
if (process.argv.length < 5) {
66+
logError(
67+
"Usage: node patchPackageRepository.js <package-folder> <repo-url> <revision>",
68+
);
69+
process.exit(1);
70+
}
71+
72+
try {
73+
patchPackageRepository(process.argv[2], process.argv[3], process.argv[4]);
74+
console.log("Patched package repository metadata");
75+
} catch (err) {
76+
logError(err.message);
77+
process.exit(1);
78+
}
79+
}
80+
81+
module.exports = {
82+
patchPackageRepository,
83+
};
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/* eslint-disable no-undef */
2+
require("should");
3+
const fs = require("fs");
4+
const path = require("path");
5+
const {
6+
getTmpDir,
7+
createTmpDir,
8+
removeTmpDir,
9+
writeJsonFile,
10+
} = require("./utils");
11+
const { patchPackageRepository } = require("../patchPackageRepository");
12+
13+
describe("patchPackageRepository.js", function () {
14+
const tmpDir = getTmpDir("test-patch-package-repository");
15+
const repoUrl = "https://github.com/openupm/test-package";
16+
const revision = "0123456789abcdef0123456789abcdef01234567";
17+
18+
beforeEach(function () {
19+
removeTmpDir("test-patch-package-repository");
20+
createTmpDir("test-patch-package-repository");
21+
});
22+
23+
afterEach(function () {
24+
removeTmpDir("test-patch-package-repository");
25+
});
26+
27+
it("adds repository metadata when missing", function () {
28+
writeJsonFile(path.resolve(tmpDir, "package.json"), {
29+
name: "package-a",
30+
version: "1.0.0",
31+
});
32+
33+
const result = patchPackageRepository(tmpDir, repoUrl, revision);
34+
35+
result.repository.should.deepEqual({
36+
type: "git",
37+
url: repoUrl,
38+
revision,
39+
});
40+
41+
const saved = JSON.parse(
42+
fs.readFileSync(path.resolve(tmpDir, "package.json"), "utf8"),
43+
);
44+
saved.repository.should.deepEqual(result.repository);
45+
});
46+
47+
it("replaces existing repository metadata", function () {
48+
writeJsonFile(path.resolve(tmpDir, "package.json"), {
49+
name: "package-a",
50+
version: "1.0.0",
51+
repository: "https://example.invalid/old.git",
52+
});
53+
54+
const result = patchPackageRepository(tmpDir, repoUrl, revision);
55+
56+
result.repository.should.deepEqual({
57+
type: "git",
58+
url: repoUrl,
59+
revision,
60+
});
61+
});
62+
63+
it("preserves unrelated manifest fields", function () {
64+
writeJsonFile(path.resolve(tmpDir, "package.json"), {
65+
name: "package-a",
66+
version: "1.0.0",
67+
displayName: "Package A",
68+
dependencies: {
69+
"package-b": "2.0.0",
70+
},
71+
});
72+
73+
const result = patchPackageRepository(tmpDir, repoUrl, revision);
74+
75+
result.name.should.equal("package-a");
76+
result.version.should.equal("1.0.0");
77+
result.displayName.should.equal("Package A");
78+
result.dependencies.should.deepEqual({
79+
"package-b": "2.0.0",
80+
});
81+
});
82+
83+
it("rejects a missing package manifest", function () {
84+
(() => patchPackageRepository(tmpDir, repoUrl, revision)).should.throw(
85+
/ENOENT/,
86+
);
87+
});
88+
89+
it("rejects an invalid package manifest", function () {
90+
fs.writeFileSync(path.resolve(tmpDir, "package.json"), "{");
91+
92+
(() => patchPackageRepository(tmpDir, repoUrl, revision)).should.throw();
93+
});
94+
});

0 commit comments

Comments
 (0)