@backstage/repo-tools 0.8.1-next.1 → 0.9.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,30 @@
1
1
  # @backstage/repo-tools
2
2
 
3
+ ## 0.9.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 683870a: Adds 2 new commands `repo schema openapi diff` and `package schema openapi diff`. `repo schema openapi diff` is intended to power a new breaking changes check on pull requests and the package level command allows plugin developers to quickly see new API breaking changes. They're intended to be used in complement with the existing `repo schema openapi verify` command to validate your OpenAPI spec against a variety of things.
8
+
9
+ ### Patch Changes
10
+
11
+ - 9ae9bb2: Update the paths logic in the api reports command to support complex subpaths
12
+ - d229dc4: Move path utilities from `backend-common` to the `backend-plugin-api` package.
13
+ - Updated dependencies
14
+ - @backstage/catalog-model@1.5.0
15
+ - @backstage/backend-plugin-api@0.6.18
16
+
17
+ ## 0.9.0-next.2
18
+
19
+ ### Minor Changes
20
+
21
+ - 683870a: Adds 2 new commands `repo schema openapi diff` and `package schema openapi diff`. `repo schema openapi diff` is intended to power a new breaking changes check on pull requests and the package level command allows plugin developers to quickly see new API breaking changes. They're intended to be used in complement with the existing `repo schema openapi verify` command to validate your OpenAPI spec against a variety of things.
22
+
23
+ ### Patch Changes
24
+
25
+ - Updated dependencies
26
+ - @backstage/backend-common@0.22.0-next.2
27
+
3
28
  ## 0.8.1-next.1
4
29
 
5
30
  ### Patch Changes
@@ -1,9 +1,5 @@
1
1
  'use strict';
2
2
 
3
- var fs = require('fs-extra');
4
- var paths = require('./paths-BvbxdT_S.cjs.js');
5
- var path = require('path');
6
-
7
3
  const YAML_SCHEMA_PATH = "src/schema/openapi.yaml";
8
4
  const TS_MODULE = "src/schema/openapi.generated";
9
5
  const TS_SCHEMA_PATH = `${TS_MODULE}.ts`;
@@ -40,31 +36,9 @@ const OPENAPI_IGNORE_FILES = [
40
36
  "tsconfig.json"
41
37
  ];
42
38
 
43
- const getPathToFile = async (directory, filename) => {
44
- return path.resolve(directory, filename);
45
- };
46
- const getRelativePathToFile = async (filename) => {
47
- return await getPathToFile(paths.paths.targetDir, filename);
48
- };
49
- const assertExists = async (path) => {
50
- if (!await fs.pathExists(path)) {
51
- throw new Error(`Could not find ${path}.`);
52
- }
53
- return path;
54
- };
55
- const getPathToOpenApiSpec = async (directory) => {
56
- return await assertExists(await getPathToFile(directory, YAML_SCHEMA_PATH));
57
- };
58
- const getPathToCurrentOpenApiSpec = async () => {
59
- return await assertExists(await getRelativePathToFile(YAML_SCHEMA_PATH));
60
- };
61
-
62
39
  exports.OPENAPI_IGNORE_FILES = OPENAPI_IGNORE_FILES;
63
40
  exports.OUTPUT_PATH = OUTPUT_PATH;
64
41
  exports.TS_MODULE = TS_MODULE;
65
42
  exports.TS_SCHEMA_PATH = TS_SCHEMA_PATH;
66
43
  exports.YAML_SCHEMA_PATH = YAML_SCHEMA_PATH;
67
- exports.getPathToCurrentOpenApiSpec = getPathToCurrentOpenApiSpec;
68
- exports.getPathToOpenApiSpec = getPathToOpenApiSpec;
69
- exports.getRelativePathToFile = getRelativePathToFile;
70
- //# sourceMappingURL=helpers-Dd7PBM8s.cjs.js.map
44
+ //# sourceMappingURL=constants-Dwa51b6l.cjs.js.map
@@ -0,0 +1,84 @@
1
+ 'use strict';
2
+
3
+ var chalk = require('chalk');
4
+ var exec = require('./exec-B_ZXslMw.cjs.js');
5
+ var helpers = require('./helpers-ja_ryoK_.cjs.js');
6
+ var paths = require('./paths-BvbxdT_S.cjs.js');
7
+ var process$1 = require('process');
8
+ var promises = require('fs/promises');
9
+ var path = require('path');
10
+ require('util');
11
+ require('child_process');
12
+ require('fs-extra');
13
+ require('./constants-Dwa51b6l.cjs.js');
14
+ require('@backstage/cli-common');
15
+ require('@backstage/cli-node');
16
+ require('minimatch');
17
+
18
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
19
+
20
+ var chalk__default = /*#__PURE__*/_interopDefaultCompat(chalk);
21
+
22
+ const reduceOpticOutput = (output) => {
23
+ return output.split("\n").filter((e) => !e.startsWith("Rerun") && e.trim()).join("\n");
24
+ };
25
+ async function check(opts) {
26
+ const resolvedOpenapiPath = await helpers.getPathToCurrentOpenApiSpec();
27
+ let baseRef = opts.since;
28
+ if (!baseRef) {
29
+ const { stdout: branch } = await exec.exec(
30
+ "git merge-base --fork-point origin/master"
31
+ );
32
+ baseRef = branch.toString().trim();
33
+ }
34
+ let failed = false;
35
+ let output = "";
36
+ try {
37
+ const { stdout } = await exec.exec(
38
+ "yarn optic diff",
39
+ [
40
+ resolvedOpenapiPath,
41
+ "--check",
42
+ opts.json ? "--json" : "",
43
+ "--base",
44
+ baseRef
45
+ ],
46
+ {
47
+ cwd: paths.paths.targetRoot,
48
+ env: { CI: opts.json ? "1" : void 0, ...process$1.env }
49
+ }
50
+ );
51
+ output = stdout.toString();
52
+ } catch (err) {
53
+ output = err.stdout;
54
+ failed = true;
55
+ }
56
+ if (opts.json) {
57
+ const file = (await promises.readFile(path.resolve(paths.paths.targetRoot, "ci-run-details.json"))).toString();
58
+ const results = JSON.parse(file);
59
+ console.log(file);
60
+ if (!opts.ignore && results.failed) {
61
+ throw new Error("Some checks failed");
62
+ }
63
+ await promises.rm(path.resolve(paths.paths.targetRoot, "ci-run-details.json"));
64
+ } else {
65
+ console.log(reduceOpticOutput(output));
66
+ if (!opts.ignore && failed) {
67
+ throw new Error("Some checks failed");
68
+ }
69
+ }
70
+ }
71
+ async function command(opts) {
72
+ try {
73
+ await check(opts);
74
+ if (!opts.json)
75
+ console.log(chalk__default.default.green(`All checks passed.`));
76
+ } catch (err) {
77
+ if (!opts.json)
78
+ console.log(chalk__default.default.red(err.message));
79
+ process.exit(1);
80
+ }
81
+ }
82
+
83
+ exports.command = command;
84
+ //# sourceMappingURL=diff-BrXlSJqI.cjs.js.map
@@ -0,0 +1,271 @@
1
+ 'use strict';
2
+
3
+ var cliNode = require('@backstage/cli-node');
4
+ var exec = require('./exec-B_ZXslMw.cjs.js');
5
+ var openapiUtilities = require('@useoptic/openapi-utilities');
6
+ var paths = require('./paths-BvbxdT_S.cjs.js');
7
+ var constants = require('./constants-Dwa51b6l.cjs.js');
8
+ require('util');
9
+ require('child_process');
10
+ require('@backstage/cli-common');
11
+ require('minimatch');
12
+ require('path');
13
+
14
+ const getChecksLabel = (results, severity) => {
15
+ const totalChecks = results.length;
16
+ let failingChecks = 0;
17
+ let exemptedFailingChecks = 0;
18
+ for (const result of results) {
19
+ if (result.passed)
20
+ continue;
21
+ if (result.severity < severity)
22
+ continue;
23
+ if (result.exempted)
24
+ exemptedFailingChecks += 1;
25
+ else
26
+ failingChecks += 1;
27
+ }
28
+ const exemptedChunk = exemptedFailingChecks > 0 ? `, ${exemptedFailingChecks} exempted` : "";
29
+ return failingChecks > 0 ? `\u26A0\uFE0F **${failingChecks}**/**${totalChecks}** failed${exemptedChunk}` : totalChecks > 0 ? `\u2705 **${totalChecks}** passed${exemptedChunk}` : `\u2139\uFE0F No automated checks have run`;
30
+ };
31
+ function getOperationsText(groupedDiffs, options) {
32
+ const ops = openapiUtilities.getOperationsChanged(groupedDiffs);
33
+ const operationsText = [
34
+ ...[...ops.added].map((o) => `\`${o}\` (added)`),
35
+ ...[...ops.changed].map((o) => `\`${o}\` (changed)`),
36
+ ...[...ops.removed].map((o) => `\`${o}\` (removed)`)
37
+ ].join("\n") ;
38
+ return `${openapiUtilities.getOperationsChangedLabel(groupedDiffs)}
39
+
40
+ ${operationsText}
41
+ `;
42
+ }
43
+ const getCaptureIssuesLabel = ({
44
+ unmatchedInteractions,
45
+ mismatchedEndpoints
46
+ }) => {
47
+ return [
48
+ ...unmatchedInteractions ? [
49
+ `\u{1F195} ${unmatchedInteractions} undocumented path${unmatchedInteractions > 1 ? "s" : ""}`
50
+ ] : [],
51
+ ...mismatchedEndpoints ? [
52
+ `\u26A0\uFE0F ${mismatchedEndpoints} mismatch${mismatchedEndpoints > 1 ? "es" : ""}`
53
+ ] : []
54
+ ].join("\n");
55
+ };
56
+ const getBreakagesRow = (breakage) => {
57
+ return `
58
+ - ${breakage.apiName}
59
+ ${breakage.comparison.results.map(
60
+ (s) => `
61
+ - ${s.where}
62
+ ${"```"}
63
+ ${s.error}
64
+ ${"```"}`
65
+ )}`;
66
+ };
67
+ const addSummaryLine = (items, label) => {
68
+ const length = Array.isArray(items) ? items.length : items;
69
+ if (!length)
70
+ return "";
71
+ let text = length === 1 ? `1 API` : `${length} APIs`;
72
+ text += ` had ${label}`;
73
+ return text;
74
+ };
75
+ const generateCompareSummaryMarkdown = (commit, results, options) => {
76
+ const anyCompletedHasWarning = results.completed.some(
77
+ (s) => s.warnings.length > 0
78
+ );
79
+ const anyCompletedHasCapture = results.completed.some((s) => s.capture);
80
+ if (results.completed.length === 0 && results.failed.length === 0 && results.failed.length === 0) {
81
+ return `No API changes detected for commit (${commit.sha})`;
82
+ }
83
+ const breakages = results.completed.filter((s) => s.comparison.results.some((e) => !e.passed)).map((e) => ({
84
+ ...e,
85
+ comparison: {
86
+ ...e.comparison,
87
+ results: e.comparison.results.filter((f) => !f.passed)
88
+ }
89
+ }));
90
+ const successfullyCompletedCount = results.completed.length - breakages.length;
91
+ return `### Summary for commit (${commit.sha})
92
+
93
+ ${addSummaryLine(results.noop, "no changes")}
94
+
95
+ ${addSummaryLine(breakages.length, "breaking changes")}
96
+
97
+ ${addSummaryLine(successfullyCompletedCount, "non-breaking changes")}
98
+
99
+ ${addSummaryLine(results.warning, "warnings")}
100
+
101
+ ${results.completed.length > 0 ? `### APIs with Changes
102
+
103
+ <table>
104
+ <thead>
105
+ <tr>
106
+ <th>API</th>
107
+ <th>Changes</th>
108
+ <th>Rules</th>
109
+ ${anyCompletedHasWarning ? "<th>Warnings</th>" : ""}
110
+ ${anyCompletedHasCapture ? "<th>Tests</th>" : ""}
111
+ </tr>
112
+ </thead>
113
+ <tbody>
114
+ ${results.completed.map(
115
+ (s) => `<tr>
116
+ <td>
117
+ ${s.apiName}
118
+ </td>
119
+ <td>
120
+ ${getOperationsText(s.comparison.groupedDiffs, {
121
+ webUrl: s.opticWebUrl,
122
+ verbose: options.verbose,
123
+ labelJoiner: ",\n"
124
+ })}
125
+ </td>
126
+ <td>
127
+ ${getChecksLabel(s.comparison.results, results.severity)}
128
+ </td>
129
+
130
+ ${anyCompletedHasWarning ? `<td>${s.warnings.join("\n")}</td>` : ""}
131
+
132
+ ${anyCompletedHasCapture ? `
133
+ <td>
134
+ ${s.capture ? s.capture.success ? s.capture.mismatchedEndpoints || s.capture.unmatchedInteractions ? getCaptureIssuesLabel({
135
+ unmatchedInteractions: s.capture.unmatchedInteractions,
136
+ mismatchedEndpoints: s.capture.mismatchedEndpoints
137
+ }) : `\u2705 ${s.capture.percentCovered}% coverage` : "\u274C\xA0Failed to run" : ""}
138
+ </td>
139
+ ` : ""}
140
+ </tr>`
141
+ ).join("\n")}
142
+ </tbody>
143
+ </table>` : ""}
144
+
145
+ ${results.failed.length > 0 ? `### APIs with Errors
146
+
147
+ <table>
148
+ <thead>
149
+ <tr>
150
+ <th>API</th>
151
+ <th>Error</th>
152
+ </tr>
153
+ </thead>
154
+ <tbody>
155
+ ${results.failed.map(
156
+ (s) => `<tr>
157
+ <td>${s.apiName}</td>
158
+ <td>
159
+
160
+ ${"```"}
161
+ ${s.error}
162
+ ${"```"}
163
+
164
+ </td>
165
+ </tr>`
166
+ ).join("\n")}
167
+ </tbody>
168
+ </table>
169
+ ` : ""}
170
+
171
+ ${results.warning && results.warning.length ? `
172
+ ### APIs with Warnings
173
+ <table>
174
+ <thead>
175
+ <tr>
176
+ <th>API</th>
177
+ <th>Warning</th>
178
+ </tr>
179
+ </thead>
180
+ <tbody>
181
+ ${results.warning.map((e) => `<tr><td>${e.apiName}</td><td>${e.warning}</td></tr>`).join("\n")}
182
+ </tbody>
183
+ </table>` : ""}
184
+ ${breakages.length > 0 ? `
185
+ ### Routes with Breakages
186
+
187
+ ${breakages.map(getBreakagesRow).join("\n")}
188
+ ` : ""}
189
+ `;
190
+ };
191
+
192
+ function cleanUpApiName(e) {
193
+ e.apiName = e.apiName.replace(paths.paths.targetDir, "").replace(constants.YAML_SCHEMA_PATH, "");
194
+ }
195
+ async function command(opts) {
196
+ var _a, _b, _c, _d, _e;
197
+ let packages = await cliNode.PackageGraph.listTargetPackages();
198
+ let since = "";
199
+ if (opts.since) {
200
+ const { stdout: sinceRaw } = await exec.exec("git", ["rev-parse", opts.since]);
201
+ since = sinceRaw.toString().trim();
202
+ const { stdout: changedFilesRaw } = await exec.exec("git", [
203
+ "diff",
204
+ "--name-only",
205
+ since
206
+ ]);
207
+ const changedFiles = changedFilesRaw.toString().trim();
208
+ const changedOpenApiSpecs = changedFiles.split("\n").filter((e) => e.endsWith(constants.YAML_SCHEMA_PATH)).map((e) => paths.paths.resolveTarget(e));
209
+ packages = packages.filter(
210
+ (pkg) => changedOpenApiSpecs.some((e) => e.startsWith(`${pkg.dir}/`))
211
+ );
212
+ }
213
+ const checkablePackages = packages.filter((e) => {
214
+ var _a2;
215
+ return (_a2 = e.packageJson.scripts) == null ? void 0 : _a2.diff;
216
+ });
217
+ try {
218
+ const outputs = {
219
+ completed: [],
220
+ failed: [],
221
+ noop: [],
222
+ warning: [],
223
+ severity: 0
224
+ };
225
+ for (const pkg of checkablePackages) {
226
+ const sinceCommands = since ? ["--since", since] : [];
227
+ const { stdout } = await exec.exec(
228
+ "yarn",
229
+ ["diff", "--ignore", "--json", ...sinceCommands],
230
+ {
231
+ cwd: pkg.dir
232
+ }
233
+ );
234
+ const result = JSON.parse(stdout.toString());
235
+ outputs.completed.push(...(_a = result.completed) != null ? _a : []);
236
+ outputs.failed.push(...(_b = result.failed) != null ? _b : []);
237
+ outputs.noop.push(...(_c = result.noop) != null ? _c : []);
238
+ }
239
+ for (const pkg of packages.filter((e) => {
240
+ var _a2;
241
+ return !((_a2 = e.packageJson.scripts) == null ? void 0 : _a2.diff);
242
+ })) {
243
+ (_d = outputs.warning) == null ? void 0 : _d.push({
244
+ apiName: `${pkg.dir}/`,
245
+ warning: "No diff script found in package.json"
246
+ });
247
+ }
248
+ outputs.completed.forEach(cleanUpApiName);
249
+ outputs.failed.forEach(cleanUpApiName);
250
+ outputs.noop.forEach(cleanUpApiName);
251
+ (_e = outputs.warning) == null ? void 0 : _e.forEach(cleanUpApiName);
252
+ const { stdout: currentSha } = await exec.exec("git", ["rev-parse", "HEAD"]);
253
+ console.log(
254
+ generateCompareSummaryMarkdown(
255
+ { sha: currentSha.toString().trim() },
256
+ outputs,
257
+ { verbose: true }
258
+ )
259
+ );
260
+ const failed = outputs.failed.length > 0;
261
+ if (failed) {
262
+ throw new Error("Some checks failed");
263
+ }
264
+ } catch (err) {
265
+ console.error(err);
266
+ process.exit(1);
267
+ }
268
+ }
269
+
270
+ exports.command = command;
271
+ //# sourceMappingURL=diff-D9fyiOf7.cjs.js.map
@@ -4,7 +4,7 @@ var fs = require('fs-extra');
4
4
  var paths = require('./paths-BvbxdT_S.cjs.js');
5
5
  var chalk = require('chalk');
6
6
  var exec = require('./exec-B_ZXslMw.cjs.js');
7
- var helpers = require('./helpers-Dd7PBM8s.cjs.js');
7
+ var helpers = require('./helpers-ja_ryoK_.cjs.js');
8
8
  var configLoader = require('@backstage/config-loader');
9
9
  var YAML = require('js-yaml');
10
10
  var path = require('path');
@@ -14,6 +14,7 @@ require('@backstage/cli-node');
14
14
  require('minimatch');
15
15
  require('util');
16
16
  require('child_process');
17
+ require('./constants-Dwa51b6l.cjs.js');
17
18
 
18
19
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
19
20
 
@@ -84,4 +85,4 @@ async function command(opts) {
84
85
  }
85
86
 
86
87
  exports.command = command;
87
- //# sourceMappingURL=fuzz-BQh7xgC3.cjs.js.map
88
+ //# sourceMappingURL=fuzz-gO9-nyTu.cjs.js.map
@@ -0,0 +1,30 @@
1
+ 'use strict';
2
+
3
+ var fs = require('fs-extra');
4
+ var paths = require('./paths-BvbxdT_S.cjs.js');
5
+ var constants = require('./constants-Dwa51b6l.cjs.js');
6
+ var path = require('path');
7
+
8
+ const getPathToFile = async (directory, filename) => {
9
+ return path.resolve(directory, filename);
10
+ };
11
+ const getRelativePathToFile = async (filename) => {
12
+ return await getPathToFile(paths.paths.targetDir, filename);
13
+ };
14
+ const assertExists = async (path) => {
15
+ if (!await fs.pathExists(path)) {
16
+ throw new Error(`Could not find ${path}.`);
17
+ }
18
+ return path;
19
+ };
20
+ const getPathToOpenApiSpec = async (directory) => {
21
+ return await assertExists(await getPathToFile(directory, constants.YAML_SCHEMA_PATH));
22
+ };
23
+ const getPathToCurrentOpenApiSpec = async () => {
24
+ return await assertExists(await getRelativePathToFile(constants.YAML_SCHEMA_PATH));
25
+ };
26
+
27
+ exports.getPathToCurrentOpenApiSpec = getPathToCurrentOpenApiSpec;
28
+ exports.getPathToOpenApiSpec = getPathToOpenApiSpec;
29
+ exports.getRelativePathToFile = getRelativePathToFile;
30
+ //# sourceMappingURL=helpers-ja_ryoK_.cjs.js.map
@@ -2,11 +2,12 @@
2
2
 
3
3
  var chalk = require('chalk');
4
4
  var path = require('path');
5
- var helpers = require('./helpers-Dd7PBM8s.cjs.js');
5
+ var constants = require('./constants-Dwa51b6l.cjs.js');
6
6
  var paths = require('./paths-BvbxdT_S.cjs.js');
7
7
  var fs = require('fs-extra');
8
8
  var exec$1 = require('./exec-B_ZXslMw.cjs.js');
9
- var backendCommon = require('@backstage/backend-common');
9
+ var backendPluginApi = require('@backstage/backend-plugin-api');
10
+ var helpers = require('./helpers-ja_ryoK_.cjs.js');
10
11
  var YAML = require('js-yaml');
11
12
  var util = require('util');
12
13
  var child_process = require('child_process');
@@ -24,18 +25,18 @@ async function generate$1(outputDirectory) {
24
25
  const resolvedOpenapiPath = await helpers.getPathToCurrentOpenApiSpec();
25
26
  const resolvedOutputDirectory = paths.paths.resolveTargetRoot(
26
27
  outputDirectory,
27
- helpers.OUTPUT_PATH
28
+ constants.OUTPUT_PATH
28
29
  );
29
30
  fs.mkdirpSync(resolvedOutputDirectory);
30
31
  await fs__default.default.mkdirp(resolvedOutputDirectory);
31
32
  await fs__default.default.writeFile(
32
33
  path.resolve(resolvedOutputDirectory, ".openapi-generator-ignore"),
33
- helpers.OPENAPI_IGNORE_FILES.join("\n")
34
+ constants.OPENAPI_IGNORE_FILES.join("\n")
34
35
  );
35
36
  await exec$1.exec(
36
37
  "node",
37
38
  [
38
- backendCommon.resolvePackagePath("@openapitools/openapi-generator-cli", "main.js"),
39
+ backendPluginApi.resolvePackagePath("@openapitools/openapi-generator-cli", "main.js"),
39
40
  "generate",
40
41
  "-i",
41
42
  resolvedOpenapiPath,
@@ -44,7 +45,7 @@ async function generate$1(outputDirectory) {
44
45
  "-g",
45
46
  "typescript",
46
47
  "-c",
47
- backendCommon.resolvePackagePath(
48
+ backendPluginApi.resolvePackagePath(
48
49
  "@backstage/repo-tools",
49
50
  "templates/typescript-backstage.yaml"
50
51
  ),
@@ -53,7 +54,7 @@ async function generate$1(outputDirectory) {
53
54
  ],
54
55
  {
55
56
  maxBuffer: Number.MAX_VALUE,
56
- cwd: backendCommon.resolvePackagePath("@backstage/repo-tools"),
57
+ cwd: backendPluginApi.resolvePackagePath("@backstage/repo-tools"),
57
58
  env: {
58
59
  ...process.env
59
60
  }
@@ -76,7 +77,7 @@ async function command$2(outputPackage) {
76
77
  try {
77
78
  await generate$1(outputPackage);
78
79
  console.log(
79
- chalk__default.default.green(`Generated client in ${outputPackage}/${helpers.OUTPUT_PATH}`)
80
+ chalk__default.default.green(`Generated client in ${outputPackage}/${constants.OUTPUT_PATH}`)
80
81
  );
81
82
  } catch (err) {
82
83
  console.log();
@@ -90,7 +91,7 @@ const exec = util.promisify(child_process.exec);
90
91
  async function generate() {
91
92
  const openapiPath = await helpers.getPathToCurrentOpenApiSpec();
92
93
  const yaml = YAML__default.default.load(await fs__default.default.readFile(openapiPath, "utf8"));
93
- const tsPath = paths.paths.resolveTarget(helpers.TS_SCHEMA_PATH);
94
+ const tsPath = paths.paths.resolveTarget(constants.TS_SCHEMA_PATH);
94
95
  await fs__default.default.writeFile(
95
96
  tsPath,
96
97
  `//
@@ -139,4 +140,4 @@ async function command(opts) {
139
140
  }
140
141
 
141
142
  exports.command = command;
142
- //# sourceMappingURL=index-CWbHgAsr.cjs.js.map
143
+ //# sourceMappingURL=index-BNyHrq4J.cjs.js.map
@@ -1,14 +1,15 @@
1
1
  'use strict';
2
2
 
3
3
  var fs = require('fs-extra');
4
- var helpers = require('./helpers-Dd7PBM8s.cjs.js');
4
+ var constants = require('./constants-Dwa51b6l.cjs.js');
5
5
  var paths = require('./paths-BvbxdT_S.cjs.js');
6
6
  var chalk = require('chalk');
7
7
  var exec = require('./exec-B_ZXslMw.cjs.js');
8
- require('path');
8
+ var helpers = require('./helpers-ja_ryoK_.cjs.js');
9
9
  require('@backstage/cli-common');
10
10
  require('@backstage/cli-node');
11
11
  require('minimatch');
12
+ require('path');
12
13
  require('util');
13
14
  require('child_process');
14
15
 
@@ -26,7 +27,7 @@ async function init() {
26
27
  await helpers.getPathToCurrentOpenApiSpec();
27
28
  } catch (err) {
28
29
  throw new Error(
29
- `OpenAPI.yaml not found in ${helpers.YAML_SCHEMA_PATH}. Please create one and retry this command.`
30
+ `OpenAPI.yaml not found in ${constants.YAML_SCHEMA_PATH}. Please create one and retry this command.`
30
31
  );
31
32
  }
32
33
  const opticConfigFilePath = await helpers.getRelativePathToFile("optic.yml");
@@ -38,9 +39,9 @@ async function init() {
38
39
  `ruleset:
39
40
  - breaking-changes
40
41
  capture:
41
- ${helpers.YAML_SCHEMA_PATH}:
42
+ ${constants.YAML_SCHEMA_PATH}:
42
43
  # \u{1F527} Runnable example with simple get requests.
43
- # Run with "PORT=3000 optic capture ${helpers.YAML_SCHEMA_PATH} --update interactive" in '${paths.paths.targetDir}'
44
+ # Run with "PORT=3000 optic capture ${constants.YAML_SCHEMA_PATH} --update interactive" in '${paths.paths.targetDir}'
44
45
  # You can change the server and the 'requests' section to experiment
45
46
  server:
46
47
  # This will not be used by 'backstage-repo-tools schema openapi test', but may be useful for interactive updates.
@@ -70,4 +71,4 @@ async function singleCommand() {
70
71
  }
71
72
 
72
73
  exports.singleCommand = singleCommand;
73
- //# sourceMappingURL=init-Canxj28t.cjs.js.map
74
+ //# sourceMappingURL=init-YP8KI_MT.cjs.js.map
@@ -10,7 +10,7 @@ var spectralRulesets = require('@stoplight/spectral-rulesets');
10
10
  var spectralFunctions = require('@stoplight/spectral-functions');
11
11
  var types = require('@stoplight/types');
12
12
  var spectralFormatters = require('@stoplight/spectral-formatters');
13
- var helpers = require('./helpers-Dd7PBM8s.cjs.js');
13
+ var helpers = require('./helpers-ja_ryoK_.cjs.js');
14
14
  require('./paths-BvbxdT_S.cjs.js');
15
15
  require('@backstage/cli-common');
16
16
  require('@backstage/cli-node');
@@ -18,6 +18,7 @@ require('minimatch');
18
18
  require('path');
19
19
  require('p-limit');
20
20
  require('portfinder');
21
+ require('./constants-Dwa51b6l.cjs.js');
21
22
 
22
23
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
23
24
 
@@ -103,4 +104,4 @@ async function bulkCommand(paths = [], options) {
103
104
  }
104
105
 
105
106
  exports.bulkCommand = bulkCommand;
106
- //# sourceMappingURL=lint-BY2lPaTV.cjs.js.map
107
+ //# sourceMappingURL=lint-CVQdMx3q.cjs.js.map
@@ -4,9 +4,10 @@ var fs = require('fs-extra');
4
4
  var path = require('path');
5
5
  var chalk = require('chalk');
6
6
  var runner = require('./runner-CRAhuK8A.cjs.js');
7
- var helpers = require('./helpers-Dd7PBM8s.cjs.js');
7
+ var constants = require('./constants-Dwa51b6l.cjs.js');
8
8
  var paths = require('./paths-BvbxdT_S.cjs.js');
9
9
  var exec = require('./exec-B_ZXslMw.cjs.js');
10
+ var helpers = require('./helpers-ja_ryoK_.cjs.js');
10
11
  require('p-limit');
11
12
  require('portfinder');
12
13
  require('@backstage/cli-common');
@@ -21,7 +22,7 @@ var fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
21
22
  var chalk__default = /*#__PURE__*/_interopDefaultCompat(chalk);
22
23
 
23
24
  async function test(directoryPath, { port }, options) {
24
- let openapiPath = path.join(directoryPath, helpers.YAML_SCHEMA_PATH);
25
+ let openapiPath = path.join(directoryPath, constants.YAML_SCHEMA_PATH);
25
26
  try {
26
27
  openapiPath = await helpers.getPathToOpenApiSpec(directoryPath);
27
28
  } catch {
@@ -43,7 +44,7 @@ async function test(directoryPath, { port }, options) {
43
44
  await exec.exec(
44
45
  `${opticLocation.trim()} capture`,
45
46
  [
46
- helpers.YAML_SCHEMA_PATH,
47
+ constants.YAML_SCHEMA_PATH,
47
48
  "--server-override",
48
49
  `http://localhost:${port}`,
49
50
  (options == null ? void 0 : options.update) ? "--update" : ""
@@ -95,4 +96,4 @@ async function bulkCommand(paths = [], options) {
95
96
  }
96
97
 
97
98
  exports.bulkCommand = bulkCommand;
98
- //# sourceMappingURL=test-B-zlD07F.cjs.js.map
99
+ //# sourceMappingURL=test-j65jkk-j.cjs.js.map
@@ -8,7 +8,8 @@ var chalk = require('chalk');
8
8
  var Parser = require('@apidevtools/swagger-parser');
9
9
  var runner = require('./runner-CRAhuK8A.cjs.js');
10
10
  var paths = require('./paths-BvbxdT_S.cjs.js');
11
- var helpers = require('./helpers-Dd7PBM8s.cjs.js');
11
+ var constants = require('./constants-Dwa51b6l.cjs.js');
12
+ var helpers = require('./helpers-ja_ryoK_.cjs.js');
12
13
  require('p-limit');
13
14
  require('portfinder');
14
15
  require('@backstage/cli-common');
@@ -31,18 +32,18 @@ async function verify(directoryPath) {
31
32
  }
32
33
  const yaml = YAML__default.default.load(await fs__default.default.readFile(openapiPath, "utf8"));
33
34
  await Parser__default.default.validate(lodash.cloneDeep(yaml));
34
- const schemaPath = path.join(directoryPath, helpers.TS_SCHEMA_PATH);
35
+ const schemaPath = path.join(directoryPath, constants.TS_SCHEMA_PATH);
35
36
  if (!await fs__default.default.pathExists(schemaPath)) {
36
- throw new Error(`No \`${helpers.TS_SCHEMA_PATH}\` file found.`);
37
+ throw new Error(`No \`${constants.TS_SCHEMA_PATH}\` file found.`);
37
38
  }
38
- const schema = await import(path.resolve(path.join(directoryPath, helpers.TS_MODULE)));
39
+ const schema = await import(path.resolve(path.join(directoryPath, constants.TS_MODULE)));
39
40
  if (!schema.spec) {
40
- throw new Error(`\`${helpers.TS_SCHEMA_PATH}\` needs to have a 'spec' export.`);
41
+ throw new Error(`\`${constants.TS_SCHEMA_PATH}\` needs to have a 'spec' export.`);
41
42
  }
42
43
  if (!lodash.isEqual(schema.spec, yaml)) {
43
44
  const path$1 = path.relative(paths.paths.targetRoot, directoryPath);
44
45
  throw new Error(
45
- `\`${helpers.YAML_SCHEMA_PATH}\` and \`${helpers.TS_SCHEMA_PATH}\` do not match. Please run \`yarn backstage-repo-tools package schema openapi generate\` from '${path$1}' to regenerate \`${helpers.TS_SCHEMA_PATH}\`.`
46
+ `\`${constants.YAML_SCHEMA_PATH}\` and \`${constants.TS_SCHEMA_PATH}\` do not match. Please run \`yarn backstage-repo-tools package schema openapi generate\` from '${path$1}' to regenerate \`${constants.TS_SCHEMA_PATH}\`.`
46
47
  );
47
48
  }
48
49
  }
@@ -65,4 +66,4 @@ async function bulkCommand(paths = []) {
65
66
  }
66
67
 
67
68
  exports.bulkCommand = bulkCommand;
68
- //# sourceMappingURL=verify-BX1iUi_q.cjs.js.map
69
+ //# sourceMappingURL=verify-Ci5ngO-H.cjs.js.map
package/dist/index.cjs.js CHANGED
@@ -54,7 +54,7 @@ function registerPackageCommand(program) {
54
54
  "Initialize any required files to use the OpenAPI tooling for this package."
55
55
  ).action(
56
56
  lazy(
57
- () => Promise.resolve().then(function () { return require('./cjs/init-Canxj28t.cjs.js'); }).then((m) => m.singleCommand)
57
+ () => Promise.resolve().then(function () { return require('./cjs/init-YP8KI_MT.cjs.js'); }).then((m) => m.singleCommand)
58
58
  )
59
59
  );
60
60
  openApiCommand.command("generate").option(
@@ -64,7 +64,7 @@ function registerPackageCommand(program) {
64
64
  "Command to generate a client and/or a server stub from an OpenAPI spec."
65
65
  ).action(
66
66
  lazy(
67
- () => Promise.resolve().then(function () { return require('./cjs/index-CWbHgAsr.cjs.js'); }).then((m) => m.command)
67
+ () => Promise.resolve().then(function () { return require('./cjs/index-BNyHrq4J.cjs.js'); }).then((m) => m.command)
68
68
  )
69
69
  );
70
70
  openApiCommand.command("fuzz").description(
@@ -76,7 +76,10 @@ function registerPackageCommand(program) {
76
76
  "--exclude-checks <excludeChecks>",
77
77
  "Exclude checks from schemathesis run"
78
78
  ).action(
79
- lazy(() => Promise.resolve().then(function () { return require('./cjs/fuzz-BQh7xgC3.cjs.js'); }).then((m) => m.command))
79
+ lazy(() => Promise.resolve().then(function () { return require('./cjs/fuzz-gO9-nyTu.cjs.js'); }).then((m) => m.command))
80
+ );
81
+ openApiCommand.command("diff").option("--ignore", "Ignore linting failures and only log the results.").option("--json", "Output the results as JSON").option("--since <ref>", "Diff the API against a specific ref").action(
82
+ lazy(() => Promise.resolve().then(function () { return require('./cjs/diff-BrXlSJqI.cjs.js'); }).then((m) => m.command))
80
83
  );
81
84
  }
82
85
  function registerRepoCommand(program) {
@@ -84,20 +87,20 @@ function registerRepoCommand(program) {
84
87
  const schemaCommand = command.command("schema [command]").description("Various tools for working with API schema");
85
88
  const openApiCommand = schemaCommand.command("openapi [command]").description("Tooling for OpenApi schema");
86
89
  openApiCommand.command("verify [paths...]").description(
87
- "Verify that all OpenAPI schemas are valid and have a matching `schemas/openapi.generated.ts` file."
90
+ "Verify that all OpenAPI schemas are valid and set up correctly."
88
91
  ).action(
89
92
  lazy(
90
- () => Promise.resolve().then(function () { return require('./cjs/verify-BX1iUi_q.cjs.js'); }).then((m) => m.bulkCommand)
93
+ () => Promise.resolve().then(function () { return require('./cjs/verify-Ci5ngO-H.cjs.js'); }).then((m) => m.bulkCommand)
91
94
  )
92
95
  );
93
96
  openApiCommand.command("lint [paths...]").description("Lint OpenAPI schemas.").option(
94
97
  "--strict",
95
98
  "Fail on any linting severity messages, not just errors."
96
99
  ).action(
97
- lazy(() => Promise.resolve().then(function () { return require('./cjs/lint-BY2lPaTV.cjs.js'); }).then((m) => m.bulkCommand))
100
+ lazy(() => Promise.resolve().then(function () { return require('./cjs/lint-CVQdMx3q.cjs.js'); }).then((m) => m.bulkCommand))
98
101
  );
99
102
  openApiCommand.command("test [paths...]").description("Test OpenAPI schemas against written tests").option("--update", "Update the spec on failure.").action(
100
- lazy(() => Promise.resolve().then(function () { return require('./cjs/test-B-zlD07F.cjs.js'); }).then((m) => m.bulkCommand))
103
+ lazy(() => Promise.resolve().then(function () { return require('./cjs/test-j65jkk-j.cjs.js'); }).then((m) => m.bulkCommand))
101
104
  );
102
105
  openApiCommand.command("fuzz").description("Fuzz all packages").option(
103
106
  "--since <ref>",
@@ -105,6 +108,15 @@ function registerRepoCommand(program) {
105
108
  ).action(
106
109
  lazy(() => Promise.resolve().then(function () { return require('./cjs/fuzz-B61zys1g.cjs.js'); }).then((m) => m.command))
107
110
  );
111
+ openApiCommand.command("diff").description(
112
+ "Diff the repository against a specific ref, will run all package `diff` scripts."
113
+ ).option(
114
+ "--since <ref>",
115
+ "Diff the API against a specific ref",
116
+ "origin/master"
117
+ ).action(
118
+ lazy(() => Promise.resolve().then(function () { return require('./cjs/diff-D9fyiOf7.cjs.js'); }).then((m) => m.command))
119
+ );
108
120
  }
109
121
  function registerCommands(program) {
110
122
  program.command("api-reports [paths...]").option("--ci", "CI run checks that there is no changes on API reports").option("--tsc", "executes the tsc compilation before extracting the APIs").option("--docs", "generates the api documentation").option(
@@ -168,7 +180,7 @@ function lazy(getActionFunc) {
168
180
  };
169
181
  }
170
182
 
171
- var version = "0.8.1-next.1";
183
+ var version = "0.9.0";
172
184
 
173
185
  const main = (argv) => {
174
186
  commander.program.name("backstage-repo-tools").version(version);
package/package.json CHANGED
@@ -1,39 +1,50 @@
1
1
  {
2
2
  "name": "@backstage/repo-tools",
3
3
  "description": "CLI for Backstage repo tooling ",
4
- "version": "0.8.1-next.1",
4
+ "version": "0.9.0",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
8
8
  "backstage": {
9
9
  "role": "cli"
10
10
  },
11
+ "keywords": [
12
+ "backstage"
13
+ ],
11
14
  "homepage": "https://backstage.io",
12
15
  "repository": {
13
16
  "type": "git",
14
17
  "url": "https://github.com/backstage/backstage",
15
18
  "directory": "packages/repo-tools"
16
19
  },
17
- "keywords": [
18
- "backstage"
19
- ],
20
20
  "license": "Apache-2.0",
21
21
  "main": "dist/index.cjs.js",
22
+ "bin": {
23
+ "backstage-repo-tools": "bin/backstage-repo-tools"
24
+ },
25
+ "files": [
26
+ "bin",
27
+ "dist/**/*.js",
28
+ "templates",
29
+ "openapitools.json"
30
+ ],
22
31
  "scripts": {
23
32
  "build": "backstage-cli package build",
24
- "lint": "backstage-cli package lint",
25
- "test": "backstage-cli package test",
26
33
  "clean": "backstage-cli package clean",
27
- "start": "nodemon --"
34
+ "lint": "backstage-cli package lint",
35
+ "start": "nodemon --",
36
+ "test": "backstage-cli package test"
28
37
  },
29
- "bin": {
30
- "backstage-repo-tools": "bin/backstage-repo-tools"
38
+ "nodemonConfig": {
39
+ "exec": "bin/backstage-repo-tools",
40
+ "ext": "ts",
41
+ "watch": "./src"
31
42
  },
32
43
  "dependencies": {
33
44
  "@apidevtools/swagger-parser": "^10.1.0",
34
45
  "@apisyouwonthate/style-guide": "^1.4.0",
35
- "@backstage/backend-common": "^0.22.0-next.1",
36
- "@backstage/catalog-model": "^1.5.0-next.0",
46
+ "@backstage/backend-plugin-api": "^0.6.18",
47
+ "@backstage/catalog-model": "^1.5.0",
37
48
  "@backstage/cli-common": "^0.1.13",
38
49
  "@backstage/cli-node": "^0.2.5",
39
50
  "@backstage/config-loader": "^1.8.0",
@@ -49,6 +60,7 @@
49
60
  "@stoplight/spectral-rulesets": "^1.18.0",
50
61
  "@stoplight/spectral-runtime": "^1.1.2",
51
62
  "@stoplight/types": "^14.0.0",
63
+ "@useoptic/openapi-utilities": "^0.54.8",
52
64
  "chalk": "^4.0.0",
53
65
  "codeowners-utils": "^1.0.2",
54
66
  "command-exists": "^1.2.9",
@@ -64,8 +76,8 @@
64
76
  "yaml-diff-patch": "^2.0.0"
65
77
  },
66
78
  "devDependencies": {
67
- "@backstage/backend-test-utils": "^0.3.8-next.1",
68
- "@backstage/cli": "^0.26.5-next.0",
79
+ "@backstage/backend-test-utils": "^0.3.8",
80
+ "@backstage/cli": "^0.26.5",
69
81
  "@backstage/types": "^1.1.1",
70
82
  "@types/is-glob": "^4.0.2",
71
83
  "@types/node": "^18.17.8",
@@ -83,16 +95,5 @@
83
95
  "prettier": {
84
96
  "optional": true
85
97
  }
86
- },
87
- "files": [
88
- "bin",
89
- "dist/**/*.js",
90
- "templates",
91
- "openapitools.json"
92
- ],
93
- "nodemonConfig": {
94
- "watch": "./src",
95
- "exec": "bin/backstage-repo-tools",
96
- "ext": "ts"
97
98
  }
98
99
  }