@backstage/repo-tools 0.3.3-next.0 → 0.3.3
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/cjs/generate-catalog-info-84fe20dd.cjs.js +163 -0
- package/dist/index.cjs.js +11 -1
- package/package.json +9 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# @backstage/repo-tools
|
|
2
2
|
|
|
3
|
+
## 0.3.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 75702e85862a: Bumped `@microsoft/api-extractor` dependency to `^7.36.4`, and `@microsoft/api-documenter` to `^7.22.33`.
|
|
8
|
+
- 1f3337ebc707: Introducing a new, experimental command `backstage-repo-tools generate-catalog-info`, which can be used to create standardized `catalog-info.yaml` files for each Backstage package in a Backstage monorepo. It can also be used to automatically fix existing `catalog-info.yaml` files with the correct metadata (including `metadata.name`, `metadata.title`, and `metadata.description` introspected from the package's `package.json`, as well as `spec.owner` introspected from `CODEOWNERS`), e.g. in a post-commit hook.
|
|
9
|
+
- ebeb77586975: Update `schema openapi generate` command to now create a default router that can be imported and used directly.
|
|
10
|
+
- Updated dependencies
|
|
11
|
+
- @backstage/cli-node@0.1.3
|
|
12
|
+
- @backstage/catalog-model@1.4.1
|
|
13
|
+
- @backstage/cli-common@0.1.12
|
|
14
|
+
- @backstage/errors@1.2.1
|
|
15
|
+
|
|
16
|
+
## 0.3.3-next.1
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- Updated dependencies
|
|
21
|
+
- @backstage/cli-node@0.1.3-next.0
|
|
22
|
+
- @backstage/cli-common@0.1.12
|
|
23
|
+
- @backstage/errors@1.2.1
|
|
24
|
+
|
|
3
25
|
## 0.3.3-next.0
|
|
4
26
|
|
|
5
27
|
### Patch Changes
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var YAML = require('js-yaml');
|
|
4
|
+
var pLimit = require('p-limit');
|
|
5
|
+
var path = require('path');
|
|
6
|
+
var yamlDiffPatch = require('yaml-diff-patch');
|
|
7
|
+
var chalk = require('chalk');
|
|
8
|
+
var cliNode = require('@backstage/cli-node');
|
|
9
|
+
var codeownersUtils = require('codeowners-utils');
|
|
10
|
+
var fs = require('fs');
|
|
11
|
+
var util = require('util');
|
|
12
|
+
|
|
13
|
+
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
14
|
+
|
|
15
|
+
var YAML__default = /*#__PURE__*/_interopDefaultLegacy(YAML);
|
|
16
|
+
var pLimit__default = /*#__PURE__*/_interopDefaultLegacy(pLimit);
|
|
17
|
+
var chalk__default = /*#__PURE__*/_interopDefaultLegacy(chalk);
|
|
18
|
+
var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
|
|
19
|
+
|
|
20
|
+
const readFile = util.promisify(fs__default["default"].readFile);
|
|
21
|
+
const writeFile = util.promisify(fs__default["default"].writeFile);
|
|
22
|
+
function isBackstagePackage(packageJson) {
|
|
23
|
+
var _a;
|
|
24
|
+
return packageJson && packageJson.hasOwnProperty("backstage") && ((_a = packageJson == null ? void 0 : packageJson.backstage) == null ? void 0 : _a.role) !== "undefined";
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function loadCodeowners() {
|
|
28
|
+
const maybeFiles = await Promise.allSettled(
|
|
29
|
+
codeownersUtils.CODEOWNERS_PATHS.map(
|
|
30
|
+
async (path$1) => readFile(path.resolve(".", path$1), { encoding: "utf-8" })
|
|
31
|
+
)
|
|
32
|
+
);
|
|
33
|
+
const file = maybeFiles.find(
|
|
34
|
+
(maybeFile) => maybeFile.status === "fulfilled"
|
|
35
|
+
);
|
|
36
|
+
if (!file) {
|
|
37
|
+
throw new Error(
|
|
38
|
+
"This utility expects a CODEOWNERS file, but no such file was found."
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
return codeownersUtils.parse(file.value);
|
|
42
|
+
}
|
|
43
|
+
function getPossibleCodeowners(codeowners, relPath) {
|
|
44
|
+
const codeownerMaybe = codeownersUtils.matchFile(relPath, codeowners);
|
|
45
|
+
return codeownerMaybe ? codeownerMaybe.owners.map(
|
|
46
|
+
(owner) => (owner.match(/(?:\@[^\/]+\/)?([^\@\/]*)$/) || [])[1]
|
|
47
|
+
) : [];
|
|
48
|
+
}
|
|
49
|
+
function getOwnerFromCodeowners(codeowners, absPath) {
|
|
50
|
+
const relPath = path.relative(".", absPath);
|
|
51
|
+
const possibleOwners = getPossibleCodeowners(codeowners, relPath);
|
|
52
|
+
const owner = possibleOwners.slice(-1)[0];
|
|
53
|
+
if (!owner) {
|
|
54
|
+
throw new Error(`${relPath} isn't owned by anyone in CODEOWNERS`);
|
|
55
|
+
}
|
|
56
|
+
return owner;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
var generateCatalogInfo = async (opts) => {
|
|
60
|
+
const { dryRun = false } = opts;
|
|
61
|
+
const packages = await cliNode.PackageGraph.listTargetPackages();
|
|
62
|
+
const codeowners = await loadCodeowners();
|
|
63
|
+
const limit = pLimit__default["default"](10);
|
|
64
|
+
const results = await Promise.allSettled(
|
|
65
|
+
packages.map(
|
|
66
|
+
({ packageJson, dir }) => limit(async () => {
|
|
67
|
+
if (!isBackstagePackage(packageJson)) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const infoYamlPath = path.resolve(dir, "catalog-info.yaml");
|
|
71
|
+
let yamlString = "";
|
|
72
|
+
try {
|
|
73
|
+
yamlString = await readFile(infoYamlPath, { encoding: "utf-8" });
|
|
74
|
+
} catch (e) {
|
|
75
|
+
if (e.code === "ENOENT") {
|
|
76
|
+
await createCatalogInfoYaml({
|
|
77
|
+
yamlPath: infoYamlPath,
|
|
78
|
+
packageJson,
|
|
79
|
+
codeowners,
|
|
80
|
+
dryRun
|
|
81
|
+
});
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
throw e;
|
|
85
|
+
}
|
|
86
|
+
await fixCatalogInfoYaml({
|
|
87
|
+
yamlPath: infoYamlPath,
|
|
88
|
+
packageJson,
|
|
89
|
+
codeowners,
|
|
90
|
+
yamlString,
|
|
91
|
+
dryRun
|
|
92
|
+
});
|
|
93
|
+
})
|
|
94
|
+
)
|
|
95
|
+
);
|
|
96
|
+
const rejects = results.filter(
|
|
97
|
+
(r) => r.status === "rejected"
|
|
98
|
+
);
|
|
99
|
+
if (rejects.length > 0) {
|
|
100
|
+
console.error(
|
|
101
|
+
chalk__default["default"].red("Unable to create or fix catalog-info.yaml files\n")
|
|
102
|
+
);
|
|
103
|
+
rejects.forEach((reject) => console.error(` ${reject.reason}`));
|
|
104
|
+
console.error();
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
function createCatalogInfoYaml(options) {
|
|
109
|
+
const { codeowners, dryRun, packageJson, yamlPath } = options;
|
|
110
|
+
const owner = getOwnerFromCodeowners(codeowners, yamlPath);
|
|
111
|
+
const entity = createOrMergeEntity(packageJson, owner);
|
|
112
|
+
return dryRun ? Promise.resolve(console.error(`Create ${path.relative(".", yamlPath)}`)) : writeFile(yamlPath, YAML__default["default"].dump(entity));
|
|
113
|
+
}
|
|
114
|
+
function fixCatalogInfoYaml(options) {
|
|
115
|
+
var _a, _b, _c;
|
|
116
|
+
const { codeowners, dryRun, packageJson, yamlPath, yamlString } = options;
|
|
117
|
+
const possibleOwners = getPossibleCodeowners(
|
|
118
|
+
codeowners,
|
|
119
|
+
path.relative(".", yamlPath)
|
|
120
|
+
);
|
|
121
|
+
const safeName = packageJson.name.replace(/[^a-z0-9_\-\.]+/g, "-").replace(/^[^a-z0-9]|[^a-z0-9]$/g, "");
|
|
122
|
+
let yamlJson;
|
|
123
|
+
try {
|
|
124
|
+
yamlJson = YAML__default["default"].load(yamlString);
|
|
125
|
+
} catch (e) {
|
|
126
|
+
throw new Error(`Unable to parse ${path.relative(".", yamlPath)}: ${e}`);
|
|
127
|
+
}
|
|
128
|
+
const badOwner = !possibleOwners.includes((_a = yamlJson.spec) == null ? void 0 : _a.owner);
|
|
129
|
+
const badTitle = yamlJson.metadata.title !== packageJson.name;
|
|
130
|
+
const badName = yamlJson.metadata.name !== safeName;
|
|
131
|
+
const badType = ((_b = yamlJson.spec) == null ? void 0 : _b.type) !== `backstage-${packageJson.backstage.role}`;
|
|
132
|
+
const badDesc = yamlJson.metadata.description !== packageJson.description;
|
|
133
|
+
if (badOwner || badTitle || badName || badType || badDesc) {
|
|
134
|
+
const owner = badOwner ? getOwnerFromCodeowners(codeowners, yamlPath) : (_c = yamlJson.spec) == null ? void 0 : _c.owner;
|
|
135
|
+
const newJson = createOrMergeEntity(packageJson, owner, yamlJson);
|
|
136
|
+
return dryRun ? Promise.resolve(console.error(`Update ${path.relative(".", yamlPath)}`)) : writeFile(yamlPath, yamlDiffPatch.yamlOverwrite(yamlString, newJson));
|
|
137
|
+
}
|
|
138
|
+
return Promise.resolve();
|
|
139
|
+
}
|
|
140
|
+
function createOrMergeEntity(packageJson, owner, existingEntity = {}) {
|
|
141
|
+
const safeEntityName = packageJson.name.replace(/[^a-z0-9_\-\.]+/g, "-").replace(/^[^a-z0-9]|[^a-z0-9]$/g, "");
|
|
142
|
+
return {
|
|
143
|
+
...existingEntity,
|
|
144
|
+
apiVersion: "backstage.io/v1alpha1",
|
|
145
|
+
kind: "Component",
|
|
146
|
+
metadata: {
|
|
147
|
+
...existingEntity.metadata,
|
|
148
|
+
// Provide default name/title/description values.
|
|
149
|
+
name: safeEntityName,
|
|
150
|
+
title: packageJson.name,
|
|
151
|
+
...packageJson.description ? { description: packageJson.description } : void 0
|
|
152
|
+
},
|
|
153
|
+
spec: {
|
|
154
|
+
lifecycle: "experimental",
|
|
155
|
+
...existingEntity.spec,
|
|
156
|
+
type: `backstage-${packageJson.backstage.role}`,
|
|
157
|
+
owner
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
exports["default"] = generateCatalogInfo;
|
|
163
|
+
//# sourceMappingURL=generate-catalog-info-84fe20dd.cjs.js.map
|
package/dist/index.cjs.js
CHANGED
|
@@ -86,6 +86,16 @@ function registerCommands(program) {
|
|
|
86
86
|
)
|
|
87
87
|
);
|
|
88
88
|
program.command("type-deps").description("Find inconsistencies in types of all packages and plugins").action(lazy(() => Promise.resolve().then(function () { return require('./cjs/type-deps-5eacd931.cjs.js'); }).then((m) => m.default)));
|
|
89
|
+
program.command("generate-catalog-info").option(
|
|
90
|
+
"--dry-run",
|
|
91
|
+
"Shows what would happen without actually writing any yaml."
|
|
92
|
+
).description("Create or fix info yaml files for all backstage packages").action(
|
|
93
|
+
lazy(
|
|
94
|
+
() => Promise.resolve().then(function () { return require('./cjs/generate-catalog-info-84fe20dd.cjs.js'); }).then(
|
|
95
|
+
(m) => m.default
|
|
96
|
+
)
|
|
97
|
+
)
|
|
98
|
+
);
|
|
89
99
|
registerSchemaCommand(program);
|
|
90
100
|
}
|
|
91
101
|
function lazy(getActionFunc) {
|
|
@@ -101,7 +111,7 @@ function lazy(getActionFunc) {
|
|
|
101
111
|
};
|
|
102
112
|
}
|
|
103
113
|
|
|
104
|
-
var version = "0.3.3
|
|
114
|
+
var version = "0.3.3";
|
|
105
115
|
|
|
106
116
|
const main = (argv) => {
|
|
107
117
|
commander.program.name("backstage-repo-tools").version(version);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/repo-tools",
|
|
3
3
|
"description": "CLI for Backstage repo tooling ",
|
|
4
|
-
"version": "0.3.3
|
|
4
|
+
"version": "0.3.3",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -32,12 +32,13 @@
|
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@apidevtools/swagger-parser": "^10.1.0",
|
|
34
34
|
"@apisyouwonthate/style-guide": "^1.4.0",
|
|
35
|
+
"@backstage/catalog-model": "^1.4.1",
|
|
35
36
|
"@backstage/cli-common": "^0.1.12",
|
|
36
|
-
"@backstage/cli-node": "^0.1.
|
|
37
|
+
"@backstage/cli-node": "^0.1.3",
|
|
37
38
|
"@backstage/errors": "^1.2.1",
|
|
38
39
|
"@manypkg/get-packages": "^1.1.3",
|
|
39
|
-
"@microsoft/api-documenter": "^7.
|
|
40
|
-
"@microsoft/api-extractor": "^7.
|
|
40
|
+
"@microsoft/api-documenter": "^7.22.33",
|
|
41
|
+
"@microsoft/api-extractor": "^7.36.4",
|
|
41
42
|
"@stoplight/spectral-core": "^1.18.0",
|
|
42
43
|
"@stoplight/spectral-formatters": "^1.1.0",
|
|
43
44
|
"@stoplight/spectral-functions": "^1.7.2",
|
|
@@ -46,6 +47,7 @@
|
|
|
46
47
|
"@stoplight/spectral-runtime": "^1.1.2",
|
|
47
48
|
"@stoplight/types": "^13.14.0",
|
|
48
49
|
"chalk": "^4.0.0",
|
|
50
|
+
"codeowners-utils": "^1.0.2",
|
|
49
51
|
"commander": "^9.1.0",
|
|
50
52
|
"fs-extra": "10.1.0",
|
|
51
53
|
"glob": "^8.0.3",
|
|
@@ -54,10 +56,11 @@
|
|
|
54
56
|
"lodash": "^4.17.21",
|
|
55
57
|
"minimatch": "^5.1.1",
|
|
56
58
|
"p-limit": "^3.0.2",
|
|
57
|
-
"ts-node": "^10.0.0"
|
|
59
|
+
"ts-node": "^10.0.0",
|
|
60
|
+
"yaml-diff-patch": "^2.0.0"
|
|
58
61
|
},
|
|
59
62
|
"devDependencies": {
|
|
60
|
-
"@backstage/cli": "^0.22.10
|
|
63
|
+
"@backstage/cli": "^0.22.10",
|
|
61
64
|
"@backstage/types": "^1.1.0",
|
|
62
65
|
"@types/is-glob": "^4.0.2",
|
|
63
66
|
"@types/mock-fs": "^4.13.0",
|