Merge pull request #26130 from backstage/mob/backend-lint

repo-tools: Add backend-lint command
This commit is contained in:
Camila Belo
2024-08-23 10:03:23 +02:00
committed by GitHub
5 changed files with 164 additions and 1 deletions
+23
View File
@@ -18,6 +18,7 @@ Commands:
knip-reports [options] [paths...]
package [command]
repo [command]
lint [command]
help [command]
```
@@ -60,6 +61,28 @@ Options:
-h, --help
```
### `backstage-repo-tools lint`
```
Usage: backstage-repo-tools lint [options] [command] [command]
Options:
-h, --help
Commands:
legacy-backend-exports [paths...]
help [command]
```
### `backstage-repo-tools lint legacy-backend-exports`
```
Usage: backstage-repo-tools lint legacy-backend-exports [options] [paths...]
Options:
-h, --help
```
### `backstage-repo-tools package`
```
+1
View File
@@ -73,6 +73,7 @@
"minimatch": "^9.0.0",
"p-limit": "^3.0.2",
"portfinder": "^1.0.32",
"ts-morph": "^23.0.0",
"yaml-diff-patch": "^2.0.0"
},
"devDependencies": {
+18
View File
@@ -162,6 +162,23 @@ function registerRepoCommand(program: Command) {
);
}
function registerLintCommand(program: Command) {
const lintCommand = program
.command('lint [command]')
.description('Tools for linting repository.');
lintCommand
.command('legacy-backend-exports [paths...]')
.description(
'Lint backend plugin packages for legacy exports and make sure it conforms to the new export pattern',
)
.action(
lazy(() =>
import(
'./lint-legacy-backend-exports/lint-legacy-backend-exports'
).then(m => m.lint),
),
);
}
export function registerCommands(program: Command) {
program
.command('api-reports [paths...]')
@@ -238,6 +255,7 @@ export function registerCommands(program: Command) {
registerPackageCommand(program);
registerRepoCommand(program);
registerLintCommand(program);
}
// Wraps an action function so that it always exits and handles errors
@@ -0,0 +1,98 @@
/*
* Copyright 2024 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Project } from 'ts-morph';
import { BackstagePackageJson, PackageGraph } from '@backstage/cli-node';
import fs from 'fs-extra';
import { paths as cliPaths } from '../../lib/paths';
import path from 'path';
const project = new Project({
tsConfigFilePath: cliPaths.resolveTargetRoot('tsconfig.json'),
});
function readPackageJson(pkg: string) {
return JSON.parse(fs.readFileSync(path.join(pkg, 'package.json'), 'utf-8'));
}
export async function lint(paths: string[]) {
const pkgs = (await PackageGraph.listTargetPackages()).filter(pkg => {
return (
pkg.packageJson.backstage?.role === 'backend-plugin' ||
pkg.packageJson.backstage?.role === 'backend-plugin-module'
);
});
if (paths.length > 0) {
paths.forEach(pkg => verifyIndex(pkg));
return;
}
pkgs.forEach(pkg => verifyIndex(pkg.dir, pkg.packageJson));
}
function verifyIndex(pkg: string, packageJson?: BackstagePackageJson) {
console.log(`Verifying ${pkg}`);
const tsPath = path.join(pkg, 'src/index.ts');
const sourceFile = project.getSourceFile(tsPath);
if (!sourceFile) {
console.log(`Could not find ${tsPath}`);
process.exit(1);
}
const symbols = sourceFile?.getExportSymbols();
const exportCount = symbols?.length || 0;
if (exportCount > 1) {
console.log(
` ⚠️ Warning: ${exportCount} exports found, ${symbols
.map(symbol => symbol.getName())
.join(', ')}`,
);
}
const createRouterExport = symbols?.find(
symbol => symbol.getName() === 'createRouter',
);
if (!sourceFile.getDefaultExportSymbol()) {
console.log(' ❌ Missing default export');
}
let createRouterDeprecated = undefined;
if (createRouterExport) {
createRouterDeprecated = createRouterExport
.getJsDocTags()
.find(tag => tag.getName() === 'deprecated');
}
if (createRouterExport) {
console.log(' ❌ createRouter is exported');
if (!createRouterDeprecated)
console.log(' ❌ createRouter is NOT deprecated');
}
const pkgJson = packageJson ?? readPackageJson(pkg);
if (
'@backstage/backend-common' in pkgJson.dependencies ||
'@backstage/backend-common' in pkgJson.devDependencies
) {
console.log(' ❌ Stop depending on @backstage/backend-common');
}
if (
'@backstage/backend-tasks' in pkgJson.dependencies ||
'@backstage/backend-tasks' in pkgJson.devDependencies
) {
console.log(' ❌ Stop depending on @backstage/backend-tasks');
}
}
+24 -1
View File
@@ -7886,6 +7886,7 @@ __metadata:
minimatch: ^9.0.0
p-limit: ^3.0.2
portfinder: ^1.0.32
ts-morph: ^23.0.0
yaml-diff-patch: ^2.0.0
peerDependencies:
"@microsoft/api-extractor-model": "*"
@@ -17089,6 +17090,18 @@ __metadata:
languageName: node
linkType: hard
"@ts-morph/common@npm:~0.24.0":
version: 0.24.0
resolution: "@ts-morph/common@npm:0.24.0"
dependencies:
fast-glob: ^3.3.2
minimatch: ^9.0.4
mkdirp: ^3.0.1
path-browserify: ^1.0.1
checksum: 793bc8a47c93ab55c6c036f94480d3b0e948661aef4bb7dbc29279b1dda2fc4fce809a88e221537867a313541842e12d1ecbd32b4769688abe1303807ec09db6
languageName: node
linkType: hard
"@tsconfig/node10@npm:^1.0.7":
version: 1.0.9
resolution: "@tsconfig/node10@npm:1.0.9"
@@ -34347,7 +34360,7 @@ __metadata:
languageName: node
linkType: hard
"minimatch@npm:^9.0.0, minimatch@npm:^9.0.1, minimatch@npm:^9.0.3":
"minimatch@npm:^9.0.0, minimatch@npm:^9.0.1, minimatch@npm:^9.0.3, minimatch@npm:^9.0.4":
version: 9.0.5
resolution: "minimatch@npm:9.0.5"
dependencies:
@@ -42881,6 +42894,16 @@ __metadata:
languageName: node
linkType: hard
"ts-morph@npm:^23.0.0":
version: 23.0.0
resolution: "ts-morph@npm:23.0.0"
dependencies:
"@ts-morph/common": ~0.24.0
code-block-writer: ^13.0.1
checksum: 3282eb0f8bd4577770874736c3259b97501da9a86137160b5d68f106b7848ea7b1fbccf9e198a3d930ec40c993e9951d4bfae31e2562dac8f3de0d7bb0e23615
languageName: node
linkType: hard
"ts-node@npm:^10.9.1":
version: 10.9.2
resolution: "ts-node@npm:10.9.2"