feat: move knip reports under own command

Signed-off-by: Heikki Hellgren <heikki.hellgren@op.fi>
This commit is contained in:
Heikki Hellgren
2024-01-31 10:15:45 +02:00
parent e5a84943f2
commit 55963c4714
161 changed files with 1128 additions and 1472 deletions
+6 -7
View File
@@ -1,11 +1,10 @@
# Knip report
## Unused devDependencies (4)
## Unused devDependencies (3)
| Name | Location |
|:--------------------------|:-------------|
| @backstage/cli | package.json |
| @backstage/test-utils | package.json |
| @testing-library/react | package.json |
| @testing-library/jest-dom | package.json |
| Name | Location |
|:-----------------------|:-------------|
| @backstage/cli | package.json |
| @backstage/test-utils | package.json |
| @testing-library/react | package.json |
+3 -3
View File
@@ -1,6 +1,6 @@
# Knip report
## Unused dependencies (63)
## Unused dependencies (64)
| Name | Location |
|:-------------------------------------------------|:-------------|
@@ -30,6 +30,7 @@
| @backstage/plugin-puppetdb | package.json |
| @backstage/plugin-playlist | package.json |
| @backstage/plugin-newrelic | package.json |
| @backstage/plugin-linguist | package.json |
| @backstage/plugin-devtools | package.json |
| @backstage/plugin-api-docs | package.json |
| @backstage/plugin-airbrake | package.json |
@@ -68,7 +69,7 @@
| @roadiehq/backstage-plugin-github-pull-requests | package.json |
| @backstage/plugin-techdocs-module-addons-contrib | package.json |
## Unused devDependencies (8)
## Unused devDependencies (7)
| Name | Location |
|:----------------------------|:-------------|
@@ -78,6 +79,5 @@
| @types/zen-observable | package.json |
| @backstage/test-utils | package.json |
| @testing-library/react | package.json |
| @testing-library/jest-dom | package.json |
| @testing-library/user-event | package.json |
+2 -4
View File
@@ -15,12 +15,12 @@
| @vitejs/plugin-react | package.json |
| vite-plugin-node-polyfills | package.json |
| @backstage/plugin-airbrake | package.json |
| @backstage/frontend-app-api | package.json |
| @backstage/plugin-azure-sites | package.json |
| @backstage/plugin-search-common | package.json |
| @backstage/plugin-stack-overflow | package.json |
| @backstage/plugin-linguist-common | package.json |
## Unused devDependencies (7)
## Unused devDependencies (5)
| Name | Location |
|:----------------------------|:-------------|
@@ -28,8 +28,6 @@
| @types/jquery | package.json |
| @testing-library/dom | package.json |
| @types/zen-observable | package.json |
| @testing-library/react | package.json |
| @testing-library/jest-dom | package.json |
| @testing-library/user-event | package.json |
## Unlisted dependencies (1)
+5 -6
View File
@@ -1,10 +1,9 @@
# Knip report
## Unused devDependencies (3)
## Unused devDependencies (2)
| Name | Location |
|:------------------------------|:-------------|
| @backstage/cli | package.json |
| wait-for-expect | package.json |
| @backstage/backend-test-utils | package.json |
| Name | Location |
|:----------------|:-------------|
| @backstage/cli | package.json |
| wait-for-expect | package.json |
+1 -1
View File
@@ -14,7 +14,7 @@
| pg-connection-string | package.json |
| azure-devops-node-api | package.json |
| @backstage/plugin-tech-insights-node | package.json |
| @backstage/plugin-azure-sites-backend | package.json |
| @backstage/plugin-azure-sites-common | package.json |
| @backstage/plugin-scaffolder-backend-module-rails | package.json |
## Unused devDependencies (3)
+12 -22
View File
@@ -33,10 +33,11 @@
| @spotify/eslint-config-react | package.json |
| @typescript-eslint/eslint-plugin | package.json |
## Unused devDependencies (13)
## Unused devDependencies (18)
| Name | Location |
|:----------------------------------------|:-------------|
| msw | package.json |
| del | package.json |
| ts-node | package.json |
| nodemon | package.json |
@@ -45,9 +46,13 @@
| @backstage/theme | package.json |
| @types/http-proxy | package.json |
| @backstage/dev-utils | package.json |
| @backstage/test-utils | package.json |
| @backstage/core-app-api | package.json |
| @backstage/backend-common | package.json |
| @backstage/core-plugin-api | package.json |
| @backstage/core-components | package.json |
| @types/terser-webpack-plugin | package.json |
| @backstage/backend-test-utils | package.json |
| @backstage/backend-plugin-api | package.json |
| @types/rollup-plugin-peer-deps-external | package.json |
@@ -60,26 +65,11 @@
| @vitejs/plugin-react | package.json |
| vite-plugin-node-polyfills | package.json |
## Unlisted dependencies (18)
## Unlisted dependencies (3)
| Name | Location |
|:----------------------------------|:-------------------------------------------------------------------------------------------------|
| rollup-plugin-polyfill-node | dist/cjs/build-5e63d42c.cjs.js |
| rollup-plugin-polyfill-node | dist/cjs/buildWorkspace-47e09dac.cjs.js |
| rollup-plugin-polyfill-node | dist/cjs/createDistWorkspace-09d75851.cjs.js |
| rollup-plugin-polyfill-node | dist/cjs/index-4cb89d61.cjs.js |
| react/package.json | dist/cjs/index-7e560cd7.cjs.js |
| react-dom/client | dist/cjs/packageDetection-6cb79707.cjs.js |
| prettier | dist/cjs/packageLintConfigs-eceb588c.cjs.js |
| prettier | src/commands/migrate/packageLintConfigs.ts |
| react-dom/client | src/lib/bundler/hasReactDomClient.ts |
| react/package.json | src/lib/bundler/server.ts |
| supertest | templates/default-backend-plugin/src/service/router.test.ts |
| winston | templates/default-backend-plugin/src/service/router.ts |
| express-promise-router | templates/default-backend-plugin/src/service/router.ts |
| react | templates/default-react-plugin-package/src/components/ExampleComponent/ExampleComponent.test.tsx |
| @testing-library/react | templates/default-react-plugin-package/src/components/ExampleComponent/ExampleComponent.test.tsx |
| react | templates/default-react-plugin-package/src/components/ExampleComponent/ExampleComponent.tsx |
| @material-ui/core | templates/default-react-plugin-package/src/components/ExampleComponent/ExampleComponent.tsx |
| @backstage/plugin-scaffolder-node | templates/scaffolder-module/src/actions/example/example.ts |
| Name | Location |
|:-------------------|:-------------------------------------------|
| prettier | src/commands/migrate/packageLintConfigs.ts |
| react-dom/client | src/lib/bundler/hasReactDomClient.ts |
| react/package.json | src/lib/bundler/server.ts |
+1 -2
View File
@@ -6,7 +6,7 @@
|:--------|:-------------|
| history | package.json |
## Unused devDependencies (12)
## Unused devDependencies (11)
| Name | Location |
|:-----------------------------|:-------------|
@@ -19,7 +19,6 @@
| @backstage/test-utils | package.json |
| @testing-library/react | package.json |
| react-router-dom-stable | package.json |
| @testing-library/jest-dom | package.json |
| @testing-library/user-event | package.json |
| @testing-library/react-hooks | package.json |
+1 -2
View File
@@ -6,13 +6,12 @@
|:------------------------|:-------------|
| @backstage/core-app-api | package.json |
## Unused devDependencies (9)
## Unused devDependencies (8)
| Name | Location |
|:--------------------------------------|:-------------|
| @backstage/cli | package.json |
| @testing-library/react | package.json |
| @testing-library/jest-dom | package.json |
| @backstage/plugin-catalog | package.json |
| @backstage/plugin-puppetdb | package.json |
| @backstage/frontend-app-api | package.json |
+2 -4
View File
@@ -9,7 +9,7 @@
| zen-observable | package.json |
| @backstage/config | package.json |
## Unused devDependencies (11)
## Unused devDependencies (9)
| Name | Location |
|:----------------------------|:-------------|
@@ -18,11 +18,9 @@
| @backstage/cli | package.json |
| @testing-library/dom | package.json |
| @types/zen-observable | package.json |
| @backstage/test-utils | package.json |
| @types/google-protobuf | package.json |
| @testing-library/react | package.json |
| @backstage/core-app-api | package.json |
| @testing-library/jest-dom | package.json |
| @backstage/app-defaults | package.json |
| @testing-library/user-event | package.json |
## Unlisted dependencies (1)
+1 -2
View File
@@ -6,7 +6,7 @@
|:--------|:-------------|
| history | package.json |
## Unused devDependencies (7)
## Unused devDependencies (6)
| Name | Location |
|:----------------------------|:-------------|
@@ -15,6 +15,5 @@
| @backstage/test-utils | package.json |
| @testing-library/react | package.json |
| @backstage/core-app-api | package.json |
| @testing-library/jest-dom | package.json |
| @testing-library/user-event | package.json |
+1 -2
View File
@@ -6,7 +6,7 @@
|:-----------------|:-------------|
| @backstage/theme | package.json |
## Unused devDependencies (7)
## Unused devDependencies (6)
| Name | Location |
|:----------------------------|:-------------|
@@ -15,6 +15,5 @@
| @testing-library/dom | package.json |
| @backstage/test-utils | package.json |
| @testing-library/react | package.json |
| @testing-library/jest-dom | package.json |
| @testing-library/user-event | package.json |
+5 -6
View File
@@ -1,10 +1,9 @@
# Knip report
## Unlisted dependencies (3)
## Unlisted dependencies (2)
| Name | Location |
|:--------------------------|:-------------------------------|
| @typescript-eslint/parser | .eslintrc.js |
| estree | lib/visitImports.js |
| estree | rules/no-undeclared-imports.js |
| Name | Location |
|:-------|:-------------------------------|
| estree | lib/visitImports.js |
| estree | rules/no-undeclared-imports.js |
+6 -7
View File
@@ -1,11 +1,10 @@
# Knip report
## Unused devDependencies (4)
## Unused devDependencies (3)
| Name | Location |
|:--------------------------|:-------------|
| @backstage/cli | package.json |
| @backstage/test-utils | package.json |
| @testing-library/react | package.json |
| @testing-library/jest-dom | package.json |
| Name | Location |
|:-----------------------|:-------------|
| @backstage/cli | package.json |
| @backstage/test-utils | package.json |
| @testing-library/react | package.json |
+1 -2
View File
@@ -8,7 +8,7 @@
| @material-ui/core | package.json |
| @backstage/core-components | package.json |
## Unused devDependencies (7)
## Unused devDependencies (6)
| Name | Location |
|:-------------------------------|:-------------|
@@ -16,7 +16,6 @@
| @backstage/cli | package.json |
| @backstage/test-utils | package.json |
| @testing-library/react | package.json |
| @testing-library/jest-dom | package.json |
| @backstage/frontend-app-api | package.json |
| @backstage/frontend-test-utils | package.json |
+4 -5
View File
@@ -1,9 +1,8 @@
# Knip report
## Unused devDependencies (2)
## Unused devDependencies (1)
| Name | Location |
|:--------------------------|:-------------|
| @backstage/cli | package.json |
| @testing-library/jest-dom | package.json |
| Name | Location |
|:---------------|:-------------|
| @backstage/cli | package.json |
+7 -16
View File
@@ -1,20 +1,11 @@
# Knip report
## Unused dependencies (1)
## Unused devDependencies (4)
| Name | Location |
|:------------------|:-------------|
| @material-ui/core | package.json |
## Unused devDependencies (7)
| Name | Location |
|:---------------------------|:-------------|
| msw | package.json |
| @backstage/cli | package.json |
| @testing-library/dom | package.json |
| @backstage/dev-utils | package.json |
| @backstage/test-utils | package.json |
| @testing-library/jest-dom | package.json |
| @backstage/core-components | package.json |
| Name | Location |
|:----------------------|:-------------|
| msw | package.json |
| @backstage/cli | package.json |
| @testing-library/dom | package.json |
| @backstage/test-utils | package.json |
+11
View File
@@ -15,6 +15,7 @@ Commands:
api-reports [options] [paths...]
type-deps
generate-catalog-info [options]
knip-reports [options] [paths...]
package [command]
repo [command]
help [command]
@@ -49,6 +50,16 @@ Options:
-h, --help
```
### `backstage-repo-tools knip-reports`
```
Usage: backstage-repo-tools knip-reports [options] [paths...]
Options:
--ci
-h, --help
```
### `backstage-repo-tools package`
```
@@ -21,7 +21,6 @@ import {
relative as relativePath,
resolve as resolvePath,
} from 'path';
import { execFile } from 'child_process';
import fs from 'fs-extra';
import {
CompilerState,
@@ -30,8 +29,6 @@ import {
ExtractorLogLevel,
ExtractorMessage,
} from '@microsoft/api-extractor';
import os from 'os';
import pLimit from 'p-limit';
import { Program } from 'typescript';
import {
DocBlockTag,
@@ -66,6 +63,7 @@ import { AstDeclaration } from '@microsoft/api-extractor/lib/analyzer/AstDeclara
import { paths as cliPaths } from '../../lib/paths';
import minimatch from 'minimatch';
import { getPackageExportNames } from '../../lib/entryPoints';
import { createBinRunner } from '../util';
const tmpDir = cliPaths.resolveTargetRoot(
'./node_modules/.cache/api-extractor',
@@ -292,10 +290,10 @@ function logApiReportInstructions() {
'*************************************************************************************',
);
console.log(
'* You have uncommitted changes to the public API or reports of a package. *',
'* You have uncommitted changes to the public API of a package. *',
);
console.log(
'* To solve this, run `yarn build:api-reports` and commit all md file changes. *',
'* To solve this, run `yarn build:api-reports` and commit all api-report.md changes. *',
);
console.log(
'*************************************************************************************',
@@ -1229,31 +1227,6 @@ export async function categorizePackageDirs(packageDirs: string[]) {
return { tsPackageDirs, cliPackageDirs };
}
function createBinRunner(cwd: string, path: string) {
return async (...command: string[]) =>
new Promise<string>((resolve, reject) => {
execFile(
'node',
[path, ...command],
{
cwd,
shell: true,
timeout: 60000,
maxBuffer: 1024 * 1024,
},
(err, stdout, stderr) => {
if (err) {
reject(new Error(`${err.message}\n${stderr}`));
} else if (stderr) {
reject(new Error(`Command printed error output: ${stderr}`));
} else {
resolve(stdout);
}
},
);
});
}
function parseHelpPage(helpPageContent: string) {
const [, usage] = helpPageContent.match(/^\s*Usage: (.*)$/im) ?? [];
const lines = helpPageContent.split(/\r?\n/);
@@ -1445,71 +1418,3 @@ export async function runCliExtraction({
}
}
}
interface KnipExtractionOptions {
packageDirs: string[];
isLocalBuild: boolean;
}
export async function runKnipReports({
packageDirs,
isLocalBuild,
}: KnipExtractionOptions) {
const knipDir = cliPaths.resolveTargetRoot('./node_modules/knip/bin/');
const limiter = pLimit(os.cpus().length);
await Promise.all(
packageDirs.map(packageDir =>
limiter(async () => {
console.log(`## Processing ${packageDir}`);
const fullDir = cliPaths.resolveTargetRoot(packageDir);
const reportPath = resolvePath(fullDir, 'knip-report.md');
const run = createBinRunner(fullDir, '');
const report = await run(
`${knipDir}/knip.js`,
`--directory ${fullDir}`, // Run in the package directory
'--no-exit-code', // Removing this will end the process in case there are findings by knip
'--no-progress', // Remove unnecessary debugging from output
// TODO: Add more checks when dependencies start to look ok, see https://knip.dev/reference/cli#--include
'--include dependencies,unlisted',
'--reporter markdown',
);
const existingReport = await fs
.readFile(reportPath, 'utf8')
.catch(error => {
if (error.code === 'ENOENT') {
return undefined;
}
throw error;
});
if (existingReport !== report) {
if (isLocalBuild) {
console.warn(`Knip report changed for ${packageDir}`);
await fs.writeFile(reportPath, report);
} else {
logApiReportInstructions();
if (existingReport) {
console.log('');
console.log(
`The conflicting file is ${relativePath(
cliPaths.targetRoot,
reportPath,
)}, expecting the following content:`,
);
console.log('');
console.log(report);
logApiReportInstructions();
}
throw new Error(`Knip report changed for ${packageDir}, `);
}
}
}),
),
);
}
@@ -43,7 +43,6 @@ jest.mock('./api-extractor', () => ({
runApiExtraction: jest.fn(),
runCliExtraction: jest.fn(),
buildDocs: jest.fn(),
runKnipReports: jest.fn(),
}));
const projectPaths = pathsLib.paths;
@@ -21,7 +21,6 @@ import {
createTemporaryTsConfig,
runApiExtraction,
runCliExtraction,
runKnipReports,
} from './api-extractor';
import { paths as cliPaths, resolvePackagePaths } from '../../lib/paths';
import { generateTypeDeclarations } from './generateTypeDeclarations';
@@ -104,14 +103,6 @@ export const buildApiReports = async (paths: string[] = [], opts: Options) => {
});
}
if (selectedPackageDirs.length > 0) {
console.log('# Generating package knip reports');
await runKnipReports({
packageDirs: selectedPackageDirs,
isLocalBuild: !isCiBuild,
});
}
if (isDocsBuild) {
console.log('# Generating package documentation');
await buildDocs({
+11
View File
@@ -168,6 +168,17 @@ export function registerCommands(program: Command) {
),
),
);
program
.command('knip-reports [paths...]')
.option('--ci', 'CI run checks that there is no changes on knip reports')
.description('Generate a knip report for selected packages')
.action(
lazy(() =>
import('./knip-reports/knip-reports').then(m => m.buildKnipReports),
),
);
registerPackageCommand(program);
registerRepoCommand(program);
}
@@ -0,0 +1,175 @@
/*
* 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 { paths as cliPaths } from '../../lib/paths';
import pLimit from 'p-limit';
import os from 'os';
import { relative as relativePath, resolve as resolvePath } from 'path';
import fs from 'fs-extra';
import { createBinRunner } from '../util';
// Ignore this due to Knip error: Error: ENAMETOOLONG: name too long, scandir
const ignoredPackages = ['packages/techdocs-cli-embedded-app'];
interface KnipExtractionOptions {
packageDirs: string[];
isLocalBuild: boolean;
}
interface KnipConfigOptions {
packageDir: string;
}
interface KnipPackageOptions {
packageDir: string;
knipDir: string;
isLocalBuild: boolean;
}
function logKnipReportInstructions() {
console.log('');
console.log(
'*************************************************************************************',
);
console.log(
'* You have uncommitted changes to the knip reports of a package. *',
);
console.log(
'* To solve this, run `yarn build:knip-reports` and commit all md file changes. *',
);
console.log(
'*************************************************************************************',
);
console.log('');
}
async function generateKnipConfig({ packageDir }: KnipConfigOptions) {
const knipConfig = {
entry: [
'dev/index.{ts,tsx}',
'src/index.{ts,tsx}',
'src/routes.ts',
'src/run.ts',
],
jest: { entry: 'src/setupTests.ts' },
storybook: { entry: 'src/components/**/*.stories.tsx' },
ignore: [
'.eslintrc.js',
'config.d.ts',
'knexfile.js',
'node_modules/**',
'dist/**',
'{fixtures,migrations,templates}/**',
],
};
await fs.writeFile(
`${packageDir}/knip.json`,
JSON.stringify(knipConfig, null, 2),
);
}
function cleanKnipConfig({ packageDir }: KnipConfigOptions) {
if (fs.existsSync(`${packageDir}/knip.json`)) {
fs.rmSync(`${packageDir}/knip.json`);
}
}
async function handlePackage({
packageDir,
knipDir,
isLocalBuild,
}: KnipPackageOptions) {
console.log(`## Processing ${packageDir}`);
if (ignoredPackages.includes(packageDir)) {
console.log(`Skipping ${packageDir}`);
return;
}
const fullDir = cliPaths.resolveTargetRoot(packageDir);
const reportPath = resolvePath(fullDir, 'knip-report.md');
const run = createBinRunner(fullDir, '');
await generateKnipConfig({ packageDir: fullDir });
const report = await run(
`${knipDir}/knip.js`,
`--directory ${fullDir}`, // Run in the package directory
'--config knip.json',
'--no-exit-code', // Removing this will end the process in case there are findings by knip
'--no-progress', // Remove unnecessary debugging from output
// TODO: Add more checks when dependencies start to look ok, see https://knip.dev/reference/cli#--include
'--include dependencies,unlisted',
'--reporter markdown',
);
cleanKnipConfig({ packageDir: fullDir });
const existingReport = await fs.readFile(reportPath, 'utf8').catch(error => {
if (error.code === 'ENOENT') {
return undefined;
}
throw error;
});
if (existingReport !== report) {
if (isLocalBuild) {
console.warn(`Knip report changed for ${packageDir}`);
await fs.writeFile(reportPath, report);
} else {
logKnipReportInstructions();
if (existingReport) {
console.log('');
console.log(
`The conflicting file is ${relativePath(
cliPaths.targetRoot,
reportPath,
)}, expecting the following content:`,
);
console.log('');
console.log(report);
logKnipReportInstructions();
}
throw new Error(`Knip report changed for ${packageDir}, `);
}
}
}
export async function runKnipReports({
packageDirs,
isLocalBuild,
}: KnipExtractionOptions) {
const knipDir = cliPaths.resolveTargetRoot('./node_modules/knip/bin/');
const limiter = pLimit(os.cpus().length);
try {
await Promise.all(
packageDirs.map(packageDir =>
limiter(async () =>
handlePackage({ packageDir, knipDir, isLocalBuild }),
),
),
);
} catch (e) {
console.log(
`Error occurred during knip reporting: ${e}, cleaning knip configs`,
);
packageDirs.map(packageDir => {
const fullDir = cliPaths.resolveTargetRoot(packageDir);
cleanKnipConfig({ packageDir: fullDir });
});
}
}
@@ -0,0 +1,54 @@
/*
* Copyright 2022 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 { OptionValues } from 'commander';
import { runKnipReports } from './knip-extractor';
import { resolvePackagePaths } from '../../lib/paths';
type Options = {
ci?: boolean;
} & OptionValues;
export const buildKnipReports = async (paths: string[] = [], opts: Options) => {
const isCiBuild = opts.ci;
const isAllPackages = !paths?.length;
const selectedPackageDirs = await resolvePackagePaths({
paths,
include: opts.include,
exclude: opts.exclude,
});
if (isAllPackages && !isCiBuild) {
console.log('');
console.log(
'TIP: You can generate knip-reports for select packages by passing package paths:',
);
console.log('');
console.log(
' yarn build:knip-reports packages/config packages/core-plugin-api plugins/*',
);
console.log('');
}
if (selectedPackageDirs.length > 0) {
console.log('# Generating package knip reports');
await runKnipReports({
packageDirs: selectedPackageDirs,
isLocalBuild: !isCiBuild,
});
}
};
+41
View File
@@ -0,0 +1,41 @@
/*
* 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 { execFile } from 'child_process';
export function createBinRunner(cwd: string, path: string) {
return async (...command: string[]) =>
new Promise<string>((resolve, reject) => {
execFile(
'node',
[path, ...command],
{
cwd,
shell: true,
timeout: 60000,
maxBuffer: 1024 * 1024,
},
(err, stdout, stderr) => {
if (err) {
reject(new Error(`${err.message}\n${stderr}`));
} else if (stderr) {
reject(new Error(`Command printed error output: ${stderr}`));
} else {
resolve(stdout);
}
},
);
});
}
+5 -6
View File
@@ -6,11 +6,10 @@
|:------------------|:-------------|
| @material-ui/core | package.json |
## Unused devDependencies (3)
## Unused devDependencies (2)
| Name | Location |
|:--------------------------|:-------------|
| msw | package.json |
| @backstage/cli | package.json |
| @testing-library/jest-dom | package.json |
| Name | Location |
|:---------------|:-------------|
| msw | package.json |
| @backstage/cli | package.json |
+6 -7
View File
@@ -7,12 +7,11 @@
| @emotion/react | package.json |
| @emotion/styled | package.json |
## Unused devDependencies (4)
## Unused devDependencies (3)
| Name | Location |
|:--------------------------|:-------------|
| @mui/styles | package.json |
| @backstage/cli | package.json |
| @testing-library/react | package.json |
| @testing-library/jest-dom | package.json |
| Name | Location |
|:-----------------------|:-------------|
| @mui/styles | package.json |
| @backstage/cli | package.json |
| @testing-library/react | package.json |
+5 -6
View File
@@ -1,10 +1,9 @@
# Knip report
## Unused devDependencies (3)
## Unused devDependencies (2)
| Name | Location |
|:--------------------------|:-------------|
| @backstage/cli | package.json |
| @testing-library/react | package.json |
| @testing-library/jest-dom | package.json |
| Name | Location |
|:-----------------------|:-------------|
| @backstage/cli | package.json |
| @testing-library/react | package.json |