@backstage/repo-tools 0.17.0 → 0.17.1-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/dist/commands/api-reports/cli-reports/runCliExtraction.cjs.js +62 -55
- package/dist/commands/package-docs/command.cjs.js +2 -1
- package/dist/commands/peer-deps/peer-deps.cjs.js +19 -4
- package/dist/commands/util.cjs.js +40 -29
- package/dist/package.json.cjs.js +1 -1
- package/package.json +11 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# @backstage/repo-tools
|
|
2
2
|
|
|
3
|
+
## 0.17.1-next.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 2e5c5f8: Bumped `glob` dependency from v7/v8/v11 to v13 to address security vulnerabilities in older versions. Bumped `rollup` from v4.27 to v4.59+ to fix a high severity path traversal vulnerability (GHSA-mw96-cpmx-2vgc).
|
|
8
|
+
- 8e9679b: Parallelized CLI report generation, reducing wall-clock time by ~4x.
|
|
9
|
+
- Updated dependencies
|
|
10
|
+
- @backstage/backend-plugin-api@1.9.0-next.1
|
|
11
|
+
|
|
12
|
+
## 0.17.1-next.0
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- 270efef: Added support for packages that only support React 18+ in the `peer-deps` command.
|
|
17
|
+
- Updated dependencies
|
|
18
|
+
- @backstage/cli-common@0.2.1-next.0
|
|
19
|
+
- @backstage/backend-plugin-api@1.8.1-next.0
|
|
20
|
+
- @backstage/cli-node@0.3.1-next.0
|
|
21
|
+
- @backstage/config-loader@1.10.10-next.0
|
|
22
|
+
- @backstage/catalog-model@1.7.7
|
|
23
|
+
- @backstage/errors@1.2.7
|
|
24
|
+
|
|
3
25
|
## 0.17.0
|
|
4
26
|
|
|
5
27
|
### Minor Changes
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var path = require('node:path');
|
|
4
|
+
var os = require('node:os');
|
|
4
5
|
var fs = require('fs-extra');
|
|
6
|
+
var pLimit = require('p-limit');
|
|
5
7
|
var util = require('../../util.cjs.js');
|
|
6
8
|
var cliCommon = require('@backstage/cli-common');
|
|
7
9
|
var generateCliReport = require('./generateCliReport.cjs.js');
|
|
@@ -9,7 +11,9 @@ var logApiReportInstructions = require('../common/logApiReportInstructions.cjs.j
|
|
|
9
11
|
|
|
10
12
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
11
13
|
|
|
14
|
+
var os__default = /*#__PURE__*/_interopDefaultCompat(os);
|
|
12
15
|
var fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
|
|
16
|
+
var pLimit__default = /*#__PURE__*/_interopDefaultCompat(pLimit);
|
|
13
17
|
|
|
14
18
|
function parseHelpPage(helpPageContent) {
|
|
15
19
|
let usage;
|
|
@@ -59,10 +63,10 @@ function parseHelpPage(helpPageContent) {
|
|
|
59
63
|
commandArguments
|
|
60
64
|
};
|
|
61
65
|
}
|
|
62
|
-
async function exploreCliHelpPages(run) {
|
|
66
|
+
async function exploreCliHelpPages(run, limit) {
|
|
63
67
|
const helpPages = new Array();
|
|
64
68
|
async function exploreHelpPage(...path) {
|
|
65
|
-
const content = await run(...path, "--help");
|
|
69
|
+
const content = await limit(() => run(...path, "--help"));
|
|
66
70
|
const parsed = parseHelpPage(content);
|
|
67
71
|
helpPages.push({ path, ...parsed });
|
|
68
72
|
await Promise.all(
|
|
@@ -82,65 +86,68 @@ async function runCliExtraction({
|
|
|
82
86
|
packageDirs,
|
|
83
87
|
isLocalBuild
|
|
84
88
|
}) {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if (typeof pkgJson.bin === "string") {
|
|
99
|
-
const run = util.createBinRunner(fullDir, pkgJson.bin);
|
|
100
|
-
const helpPages = await exploreCliHelpPages(run);
|
|
101
|
-
models.push({ name: path.basename(pkgJson.bin), helpPages });
|
|
102
|
-
} else {
|
|
103
|
-
for (const [name, path] of Object.entries(pkgJson.bin)) {
|
|
104
|
-
const run = util.createBinRunner(fullDir, path);
|
|
105
|
-
const helpPages = await exploreCliHelpPages(run);
|
|
106
|
-
models.push({ name, helpPages });
|
|
89
|
+
const limit = pLimit__default.default(os__default.default.cpus().length);
|
|
90
|
+
await Promise.all(
|
|
91
|
+
packageDirs.map(async (packageDir) => {
|
|
92
|
+
console.log(`## Processing ${packageDir}`);
|
|
93
|
+
const fullDir = cliCommon.targetPaths.resolveRoot(packageDir);
|
|
94
|
+
const pkgJson = await fs__default.default.readJson(path.resolve(fullDir, "package.json"));
|
|
95
|
+
if (!pkgJson.bin) {
|
|
96
|
+
if (pkgJson.backstage?.role === "cli") {
|
|
97
|
+
throw new Error(
|
|
98
|
+
`CLI package ${pkgJson.name} is missing a "bin" field in its package.json`
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
return;
|
|
107
102
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
103
|
+
const models = new Array();
|
|
104
|
+
if (typeof pkgJson.bin === "string") {
|
|
105
|
+
const run = util.createBinRunner(fullDir, pkgJson.bin);
|
|
106
|
+
const helpPages = await exploreCliHelpPages(run, limit);
|
|
107
|
+
models.push({ name: path.basename(pkgJson.bin), helpPages });
|
|
108
|
+
} else {
|
|
109
|
+
for (const [name, path] of Object.entries(pkgJson.bin)) {
|
|
110
|
+
const run = util.createBinRunner(fullDir, path);
|
|
111
|
+
const helpPages = await exploreCliHelpPages(run, limit);
|
|
112
|
+
models.push({ name, helpPages });
|
|
118
113
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
if (
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
);
|
|
135
|
-
|
|
136
|
-
|
|
114
|
+
}
|
|
115
|
+
for (const model of models) {
|
|
116
|
+
const report = generateCliReport.generateCliReport({ packageName: pkgJson.name, model });
|
|
117
|
+
const reportPath = path.resolve(
|
|
118
|
+
fullDir,
|
|
119
|
+
`cli-report.${models.length === 1 ? "" : `${model.name}.`}md`
|
|
120
|
+
);
|
|
121
|
+
const existingReport = await fs__default.default.readFile(reportPath, "utf8").catch((error) => {
|
|
122
|
+
if (error.code === "ENOENT") {
|
|
123
|
+
return void 0;
|
|
124
|
+
}
|
|
125
|
+
throw error;
|
|
126
|
+
});
|
|
127
|
+
if (existingReport !== report) {
|
|
128
|
+
if (isLocalBuild) {
|
|
129
|
+
console.warn(`CLI report changed for ${packageDir}`);
|
|
130
|
+
await fs__default.default.writeFile(reportPath, report);
|
|
131
|
+
} else {
|
|
137
132
|
logApiReportInstructions.logApiReportInstructions();
|
|
133
|
+
if (existingReport) {
|
|
134
|
+
console.log("");
|
|
135
|
+
console.log(
|
|
136
|
+
`The conflicting file is ${path.relative(
|
|
137
|
+
cliCommon.targetPaths.rootDir,
|
|
138
|
+
reportPath
|
|
139
|
+
)}, expecting the following content:`
|
|
140
|
+
);
|
|
141
|
+
console.log("");
|
|
142
|
+
console.log(report);
|
|
143
|
+
logApiReportInstructions.logApiReportInstructions();
|
|
144
|
+
}
|
|
145
|
+
throw new Error(`CLI report changed for ${packageDir}`);
|
|
138
146
|
}
|
|
139
|
-
throw new Error(`CLI report changed for ${packageDir}, `);
|
|
140
147
|
}
|
|
141
148
|
}
|
|
142
|
-
}
|
|
143
|
-
|
|
149
|
+
})
|
|
150
|
+
);
|
|
144
151
|
}
|
|
145
152
|
|
|
146
153
|
exports.runCliExtraction = runCliExtraction;
|
|
@@ -97,7 +97,8 @@ async function generateDocJson(pkg) {
|
|
|
97
97
|
async function packageDocs(paths$1 = [], opts) {
|
|
98
98
|
console.warn("!!! This is an experimental command !!!");
|
|
99
99
|
const existingDocsJsonPaths = glob.glob.sync(
|
|
100
|
-
cliCommon.targetPaths.resolveRoot("dist-types/**/docs.json")
|
|
100
|
+
cliCommon.targetPaths.resolveRoot("dist-types/**/docs.json"),
|
|
101
|
+
{ windowsPathsNoEscape: true }
|
|
101
102
|
);
|
|
102
103
|
if (existingDocsJsonPaths.length > 0) {
|
|
103
104
|
console.warn(
|
|
@@ -18,6 +18,13 @@ const peerDependencies = {
|
|
|
18
18
|
"react-dom": "^17.0.0 || ^18.0.0",
|
|
19
19
|
"react-router-dom": "^6.30.2"
|
|
20
20
|
};
|
|
21
|
+
const peerDependenciesReact18Only = {
|
|
22
|
+
"@types/react": "^18.0.0",
|
|
23
|
+
react: "^18.0.0",
|
|
24
|
+
"react-dom": "^18.0.0",
|
|
25
|
+
"react-router-dom": "^6.30.2"
|
|
26
|
+
};
|
|
27
|
+
const react18OnlyPackages = /* @__PURE__ */ new Set(["@backstage/ui"]);
|
|
21
28
|
const groupsOfPeerDependencies = [["@types/react", "react", "react-dom"]];
|
|
22
29
|
const optionalPeerDependencies = /* @__PURE__ */ new Set(["@types/react"]);
|
|
23
30
|
const isOptional = (dep) => {
|
|
@@ -43,8 +50,15 @@ const isStandaloneApplication = (packageJson) => {
|
|
|
43
50
|
const matchesDependency = (dep, packageJson) => {
|
|
44
51
|
return packageJson.devDependencies && packageJson.devDependencies[dep] === desiredLocalVersionsOfDependencies[dep];
|
|
45
52
|
};
|
|
53
|
+
const getExpectedPeerDependencies = (packageJson) => {
|
|
54
|
+
if (react18OnlyPackages.has(packageJson.name)) {
|
|
55
|
+
return peerDependenciesReact18Only;
|
|
56
|
+
}
|
|
57
|
+
return peerDependencies;
|
|
58
|
+
};
|
|
46
59
|
const matchesPeerDependency = (dep, packageJson) => {
|
|
47
|
-
|
|
60
|
+
const expected = getExpectedPeerDependencies(packageJson);
|
|
61
|
+
return packageJson.peerDependencies && packageJson.peerDependencies[dep] === expected[dep];
|
|
48
62
|
};
|
|
49
63
|
var peerDeps = async ({ fix }) => {
|
|
50
64
|
let failed = false;
|
|
@@ -75,6 +89,7 @@ var peerDeps = async ({ fix }) => {
|
|
|
75
89
|
}
|
|
76
90
|
for (const pkg of packagesWithRelevantDependencies) {
|
|
77
91
|
const packageJson = pkg.packageJson;
|
|
92
|
+
const expectedPeerDeps = getExpectedPeerDependencies(packageJson);
|
|
78
93
|
for (const dep of Object.keys(peerDependencies)) {
|
|
79
94
|
if (isPeerDependency(dep, packageJson)) {
|
|
80
95
|
if (isOptional(dep) && !isMarkedAsOptional(dep, packageJson)) {
|
|
@@ -123,7 +138,7 @@ var peerDeps = async ({ fix }) => {
|
|
|
123
138
|
);
|
|
124
139
|
attemptToApplyFix(() => {
|
|
125
140
|
packageJson.peerDependencies = packageJson.peerDependencies || {};
|
|
126
|
-
packageJson.peerDependencies[groupDep] =
|
|
141
|
+
packageJson.peerDependencies[groupDep] = expectedPeerDeps[groupDep];
|
|
127
142
|
});
|
|
128
143
|
}
|
|
129
144
|
}
|
|
@@ -144,7 +159,7 @@ var peerDeps = async ({ fix }) => {
|
|
|
144
159
|
);
|
|
145
160
|
attemptToApplyFix(() => {
|
|
146
161
|
packageJson.peerDependencies = packageJson.peerDependencies || {};
|
|
147
|
-
packageJson.peerDependencies[dep] =
|
|
162
|
+
packageJson.peerDependencies[dep] = expectedPeerDeps[dep];
|
|
148
163
|
});
|
|
149
164
|
}
|
|
150
165
|
} else {
|
|
@@ -153,7 +168,7 @@ var peerDeps = async ({ fix }) => {
|
|
|
153
168
|
);
|
|
154
169
|
attemptToApplyFix(() => {
|
|
155
170
|
packageJson.peerDependencies = packageJson.peerDependencies || {};
|
|
156
|
-
packageJson.peerDependencies[dep] =
|
|
171
|
+
packageJson.peerDependencies[dep] = expectedPeerDeps[dep];
|
|
157
172
|
});
|
|
158
173
|
}
|
|
159
174
|
}
|
|
@@ -8,40 +8,51 @@ var path = require('node:path');
|
|
|
8
8
|
|
|
9
9
|
const ansiPattern = new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`, "g");
|
|
10
10
|
function createBinRunner(cwd, path$1) {
|
|
11
|
-
return
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const
|
|
11
|
+
return (...command) => {
|
|
12
|
+
return new Promise((resolve, reject) => {
|
|
13
|
+
const args = path$1 ? [path$1, ...command] : command;
|
|
14
|
+
const outPath = path.join(os.tmpdir(), `backstage-cli-out-${crypto.randomUUID()}.txt`);
|
|
15
|
+
const outFd = fs.openSync(outPath, "w");
|
|
16
|
+
const child = node_child_process.spawn("node", args, {
|
|
17
17
|
cwd,
|
|
18
18
|
env: { ...process.env, NO_COLOR: "1" },
|
|
19
19
|
stdio: ["ignore", outFd, "pipe"]
|
|
20
20
|
});
|
|
21
21
|
fs.closeSync(outFd);
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
22
|
+
const stderrChunks = [];
|
|
23
|
+
child.stderr?.on("data", (chunk) => stderrChunks.push(chunk));
|
|
24
|
+
child.on("error", (err) => {
|
|
25
|
+
try {
|
|
26
|
+
fs.unlinkSync(outPath);
|
|
27
|
+
} catch {
|
|
28
|
+
}
|
|
29
|
+
reject(new Error(`Process error: ${err.message}`));
|
|
30
|
+
});
|
|
31
|
+
child.on("close", (code, signal) => {
|
|
32
|
+
try {
|
|
33
|
+
const stdout = fs.readFileSync(outPath, "utf8").replace(ansiPattern, "");
|
|
34
|
+
const stderr = Buffer.concat(stderrChunks).toString();
|
|
35
|
+
if (signal) {
|
|
36
|
+
reject(
|
|
37
|
+
new Error(`Process was killed with signal ${signal}
|
|
38
|
+
${stderr}`)
|
|
39
|
+
);
|
|
40
|
+
} else if (code !== 0) {
|
|
41
|
+
reject(new Error(`Process exited with code ${code}
|
|
42
|
+
${stderr}`));
|
|
43
|
+
} else if (stderr.trim()) {
|
|
44
|
+
reject(new Error(`Command printed error output: ${stderr}`));
|
|
45
|
+
} else {
|
|
46
|
+
resolve(stdout);
|
|
47
|
+
}
|
|
48
|
+
} finally {
|
|
49
|
+
try {
|
|
50
|
+
fs.unlinkSync(outPath);
|
|
51
|
+
} catch {
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
});
|
|
45
56
|
};
|
|
46
57
|
}
|
|
47
58
|
|
package/dist/package.json.cjs.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/repo-tools",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.1-next.1",
|
|
4
4
|
"description": "CLI for Backstage repo tooling ",
|
|
5
5
|
"backstage": {
|
|
6
6
|
"role": "cli"
|
|
@@ -43,12 +43,12 @@
|
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"@apidevtools/swagger-parser": "^10.1.0",
|
|
45
45
|
"@apisyouwonthate/style-guide": "^1.4.0",
|
|
46
|
-
"@backstage/backend-plugin-api": "
|
|
47
|
-
"@backstage/catalog-model": "
|
|
48
|
-
"@backstage/cli-common": "
|
|
49
|
-
"@backstage/cli-node": "
|
|
50
|
-
"@backstage/config-loader": "
|
|
51
|
-
"@backstage/errors": "
|
|
46
|
+
"@backstage/backend-plugin-api": "1.9.0-next.1",
|
|
47
|
+
"@backstage/catalog-model": "1.7.7",
|
|
48
|
+
"@backstage/cli-common": "0.2.1-next.0",
|
|
49
|
+
"@backstage/cli-node": "0.3.1-next.0",
|
|
50
|
+
"@backstage/config-loader": "1.10.10-next.0",
|
|
51
|
+
"@backstage/errors": "1.2.7",
|
|
52
52
|
"@electric-sql/pglite": "^0.3.0",
|
|
53
53
|
"@manypkg/get-packages": "^1.1.3",
|
|
54
54
|
"@microsoft/api-documenter": "^7.28.1",
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
"command-exists": "^1.2.9",
|
|
70
70
|
"commander": "^14.0.3",
|
|
71
71
|
"fs-extra": "^11.2.0",
|
|
72
|
-
"glob": "^
|
|
72
|
+
"glob": "^13.0.0",
|
|
73
73
|
"globby": "^11.0.0",
|
|
74
74
|
"is-glob": "^4.0.3",
|
|
75
75
|
"js-yaml": "^4.1.0",
|
|
@@ -87,9 +87,9 @@
|
|
|
87
87
|
"zod": "^3.25.76 || ^4.0.0"
|
|
88
88
|
},
|
|
89
89
|
"devDependencies": {
|
|
90
|
-
"@backstage/backend-test-utils": "
|
|
91
|
-
"@backstage/cli": "
|
|
92
|
-
"@backstage/types": "
|
|
90
|
+
"@backstage/backend-test-utils": "1.11.2-next.1",
|
|
91
|
+
"@backstage/cli": "0.36.1-next.1",
|
|
92
|
+
"@backstage/types": "1.2.2",
|
|
93
93
|
"@types/is-glob": "^4.0.2",
|
|
94
94
|
"@types/node": "^22.13.14",
|
|
95
95
|
"@types/prettier": "^2.0.0",
|