@backstage/repo-tools 0.3.3 → 0.3.4-next.0

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 CHANGED
@@ -1,5 +1,20 @@
1
1
  # @backstage/repo-tools
2
2
 
3
+ ## 0.3.4-next.0
4
+
5
+ ### Patch Changes
6
+
7
+ - 0109d3f11159: The `generate-catalog-info` command now uses the first listed `CODEOWNER` as Component owner when initially
8
+ creating the `catalog-info.yaml` file. It continues to allow any one listed `CODEOWNER` when updating
9
+ entity metadata.
10
+ - ec13d3e86028: Fixed a bug with the `generate-catalog-info` command that could cause the `--dry-run` flag to indicate changes to files when no changes would actually be made if the command were run without the flag.
11
+ - db60a16e0a54: Added a `--ci` flag to the `generate-catalog-info` command. This flag behaves similarly to the same flag on `api-reports`: if `catalog-info.yaml` files would have been added or modified, then the process exits with status code `1`, and instructions are printed.
12
+ - Updated dependencies
13
+ - @backstage/catalog-model@1.4.1
14
+ - @backstage/cli-common@0.1.12
15
+ - @backstage/cli-node@0.1.3
16
+ - @backstage/errors@1.2.1
17
+
3
18
  ## 0.3.3
4
19
 
5
20
  ### Patch Changes
@@ -23,6 +23,8 @@ function isBackstagePackage(packageJson) {
23
23
  var _a;
24
24
  return packageJson && packageJson.hasOwnProperty("backstage") && ((_a = packageJson == null ? void 0 : packageJson.backstage) == null ? void 0 : _a.role) !== "undefined";
25
25
  }
26
+ const isRejected = (input) => input.status === "rejected";
27
+ const isFulfilled = (input) => input.status === "fulfilled";
26
28
 
27
29
  async function loadCodeowners() {
28
30
  const maybeFiles = await Promise.allSettled(
@@ -49,7 +51,7 @@ function getPossibleCodeowners(codeowners, relPath) {
49
51
  function getOwnerFromCodeowners(codeowners, absPath) {
50
52
  const relPath = path.relative(".", absPath);
51
53
  const possibleOwners = getPossibleCodeowners(codeowners, relPath);
52
- const owner = possibleOwners.slice(-1)[0];
54
+ const owner = possibleOwners[0];
53
55
  if (!owner) {
54
56
  throw new Error(`${relPath} isn't owned by anyone in CODEOWNERS`);
55
57
  }
@@ -57,15 +59,17 @@ function getOwnerFromCodeowners(codeowners, absPath) {
57
59
  }
58
60
 
59
61
  var generateCatalogInfo = async (opts) => {
60
- const { dryRun = false } = opts;
62
+ const { dryRun = false, ci = false } = opts;
61
63
  const packages = await cliNode.PackageGraph.listTargetPackages();
62
64
  const codeowners = await loadCodeowners();
63
65
  const limit = pLimit__default["default"](10);
66
+ const isDryRun = ci ? true : dryRun;
67
+ const checkForChanges = ci;
64
68
  const results = await Promise.allSettled(
65
69
  packages.map(
66
70
  ({ packageJson, dir }) => limit(async () => {
67
71
  if (!isBackstagePackage(packageJson)) {
68
- return;
72
+ return "";
69
73
  }
70
74
  const infoYamlPath = path.resolve(dir, "catalog-info.yaml");
71
75
  let yamlString = "";
@@ -73,29 +77,27 @@ var generateCatalogInfo = async (opts) => {
73
77
  yamlString = await readFile(infoYamlPath, { encoding: "utf-8" });
74
78
  } catch (e) {
75
79
  if (e.code === "ENOENT") {
76
- await createCatalogInfoYaml({
80
+ return await createCatalogInfoYaml({
77
81
  yamlPath: infoYamlPath,
78
82
  packageJson,
79
83
  codeowners,
80
- dryRun
84
+ dryRun: isDryRun
81
85
  });
82
- return;
83
86
  }
84
87
  throw e;
85
88
  }
86
- await fixCatalogInfoYaml({
89
+ return await fixCatalogInfoYaml({
87
90
  yamlPath: infoYamlPath,
88
91
  packageJson,
89
92
  codeowners,
90
93
  yamlString,
91
- dryRun
94
+ dryRun: isDryRun,
95
+ ci
92
96
  });
93
97
  })
94
98
  )
95
99
  );
96
- const rejects = results.filter(
97
- (r) => r.status === "rejected"
98
- );
100
+ const rejects = results.filter(isRejected);
99
101
  if (rejects.length > 0) {
100
102
  console.error(
101
103
  chalk__default["default"].red("Unable to create or fix catalog-info.yaml files\n")
@@ -104,16 +106,35 @@ var generateCatalogInfo = async (opts) => {
104
106
  console.error();
105
107
  process.exit(1);
106
108
  }
109
+ if (checkForChanges) {
110
+ const instructions = results.filter(isFulfilled).map((r) => r.value).filter((r) => r !== "");
111
+ if (instructions.length > 0) {
112
+ console.error(
113
+ "\ncatalog-info.yaml file(s) out of sync with CODEOWNERS and/or package.json (see instructions above)\n"
114
+ );
115
+ process.exit(1);
116
+ } else {
117
+ console.error(
118
+ "catalog-info.yaml file(s) in sync with CODEOWNERS and package.json"
119
+ );
120
+ }
121
+ }
107
122
  };
108
- function createCatalogInfoYaml(options) {
123
+ async function createCatalogInfoYaml(options) {
109
124
  const { codeowners, dryRun, packageJson, yamlPath } = options;
125
+ const instruction = `Create ${path.relative(".", yamlPath)}`;
110
126
  const owner = getOwnerFromCodeowners(codeowners, yamlPath);
111
127
  const entity = createOrMergeEntity(packageJson, owner);
112
- return dryRun ? Promise.resolve(console.error(`Create ${path.relative(".", yamlPath)}`)) : writeFile(yamlPath, YAML__default["default"].dump(entity));
128
+ if (dryRun) {
129
+ console.error(instruction);
130
+ } else {
131
+ await writeFile(yamlPath, YAML__default["default"].dump(entity));
132
+ }
133
+ return instruction;
113
134
  }
114
- function fixCatalogInfoYaml(options) {
135
+ async function fixCatalogInfoYaml(options) {
115
136
  var _a, _b, _c;
116
- const { codeowners, dryRun, packageJson, yamlPath, yamlString } = options;
137
+ const { ci, codeowners, dryRun, packageJson, yamlPath, yamlString } = options;
117
138
  const possibleOwners = getPossibleCodeowners(
118
139
  codeowners,
119
140
  path.relative(".", yamlPath)
@@ -129,13 +150,42 @@ function fixCatalogInfoYaml(options) {
129
150
  const badTitle = yamlJson.metadata.title !== packageJson.name;
130
151
  const badName = yamlJson.metadata.name !== safeName;
131
152
  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) {
153
+ if (badOwner || badTitle || badName || badType) {
134
154
  const owner = badOwner ? getOwnerFromCodeowners(codeowners, yamlPath) : (_c = yamlJson.spec) == null ? void 0 : _c.owner;
135
155
  const newJson = createOrMergeEntity(packageJson, owner, yamlJson);
136
- return dryRun ? Promise.resolve(console.error(`Update ${path.relative(".", yamlPath)}`)) : writeFile(yamlPath, yamlDiffPatch.yamlOverwrite(yamlString, newJson));
156
+ const instructions = [`Update ${path.relative(".", yamlPath)}`];
157
+ if (ci) {
158
+ if (badOwner) {
159
+ instructions.push(
160
+ ` spec.owner cannot be "${yamlJson.spec.owner}" because it must be one of (${possibleOwners.join(
161
+ ", "
162
+ )}) as listed in CODEOWNERS`
163
+ );
164
+ }
165
+ if (badTitle) {
166
+ instructions.push(
167
+ ` metadata.title cannot be "${yamlJson.metadata.title}" because it must be exactly "${packageJson.name}", the package.json name`
168
+ );
169
+ }
170
+ if (badName) {
171
+ instructions.push(
172
+ ` metadata.name cannot be "${yamlJson.metadata.name}" because it must be exactly "${safeName}", as derived from package.json name`
173
+ );
174
+ }
175
+ if (badType) {
176
+ instructions.push(
177
+ ` spec.type cannot be "${yamlJson.spec.type}" because it must be exactly "backstage-${packageJson.backstage.role}", as derived from package.json backstage.role`
178
+ );
179
+ }
180
+ }
181
+ if (dryRun) {
182
+ console.error(instructions.join("\n"));
183
+ } else {
184
+ await writeFile(yamlPath, yamlDiffPatch.yamlOverwrite(yamlString, newJson));
185
+ }
186
+ return instructions.join("\n");
137
187
  }
138
- return Promise.resolve();
188
+ return "";
139
189
  }
140
190
  function createOrMergeEntity(packageJson, owner, existingEntity = {}) {
141
191
  const safeEntityName = packageJson.name.replace(/[^a-z0-9_\-\.]+/g, "-").replace(/^[^a-z0-9]|[^a-z0-9]$/g, "");
@@ -160,4 +210,4 @@ function createOrMergeEntity(packageJson, owner, existingEntity = {}) {
160
210
  }
161
211
 
162
212
  exports["default"] = generateCatalogInfo;
163
- //# sourceMappingURL=generate-catalog-info-84fe20dd.cjs.js.map
213
+ //# sourceMappingURL=generate-catalog-info-52b0f2ff.cjs.js.map
package/dist/index.cjs.js CHANGED
@@ -89,9 +89,12 @@ function registerCommands(program) {
89
89
  program.command("generate-catalog-info").option(
90
90
  "--dry-run",
91
91
  "Shows what would happen without actually writing any yaml."
92
+ ).option(
93
+ "--ci",
94
+ "CI run checks that there are no changes to catalog-info.yaml files"
92
95
  ).description("Create or fix info yaml files for all backstage packages").action(
93
96
  lazy(
94
- () => Promise.resolve().then(function () { return require('./cjs/generate-catalog-info-84fe20dd.cjs.js'); }).then(
97
+ () => Promise.resolve().then(function () { return require('./cjs/generate-catalog-info-52b0f2ff.cjs.js'); }).then(
95
98
  (m) => m.default
96
99
  )
97
100
  )
@@ -111,7 +114,7 @@ function lazy(getActionFunc) {
111
114
  };
112
115
  }
113
116
 
114
- var version = "0.3.3";
117
+ var version = "0.3.4-next.0";
115
118
 
116
119
  const main = (argv) => {
117
120
  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.4-next.0",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -60,7 +60,7 @@
60
60
  "yaml-diff-patch": "^2.0.0"
61
61
  },
62
62
  "devDependencies": {
63
- "@backstage/cli": "^0.22.10",
63
+ "@backstage/cli": "^0.22.12-next.0",
64
64
  "@backstage/types": "^1.1.0",
65
65
  "@types/is-glob": "^4.0.2",
66
66
  "@types/mock-fs": "^4.13.0",