Fix typing and dependencies

Co-authored-by: djamaile <rdjamaile@gmail.com>
Signed-off-by: Juan Pablo Garcia Ripa <juanpablog@spotify.com>
This commit is contained in:
Juan Pablo Garcia Ripa
2022-11-16 15:12:38 +01:00
parent c72656e719
commit 3bc9319895
9 changed files with 190 additions and 1595 deletions
+2 -7
View File
@@ -11,9 +11,8 @@
"build:backend": "yarn workspace backend build",
"build:all": "backstage-cli repo build --all",
"build": "backstage-cli repo build --all",
"build:api-reports-tooling": "backstage-repo-tools api-reports",
"build:api-reports": "yarn build:api-reports:only --tsc",
"build:api-reports:only": "ts-node -T -P scripts/tsconfig.json scripts/api-extractor.ts",
"build:api-reports:only": "backstage-repo-tools api-reports",
"build:api-docs": "LANG=en_EN yarn build:api-reports --docs",
"tsc": "tsc",
"tsc:full": "backstage-cli repo clean && tsc --skipLibCheck false --incremental false",
@@ -51,11 +50,7 @@
"version": "1.8.0",
"dependencies": {
"@backstage/errors": "workspace:^",
"@manypkg/get-packages": "^1.1.3",
"@microsoft/api-documenter": "^7.17.11",
"@microsoft/api-extractor": "^7.23.0",
"@microsoft/api-extractor-model": "^7.17.2",
"@microsoft/tsdoc": "^0.14.1"
"@manypkg/get-packages": "^1.1.3"
},
"devDependencies": {
"@backstage/cli": "workspace:*",
+29
View File
@@ -0,0 +1,29 @@
## CLI Report file for "@backstage/repo-tools"
> Do not edit this file. It is a report generated by `yarn build:api-reports`
### `backstage-repo-tools`
```
Usage: backstage-repo-tools [options] [command]
Options:
-V, --version
-h, --help
Commands:
api-reports [options] [path...]
help [command]
```
### `backstage-repo-tools api-reports`
```
Usage: backstage-repo-tools api-reports [options] [path...]
Options:
--ci
--tsc
--docs
-h, --help
```
+4
View File
@@ -31,6 +31,10 @@
},
"dependencies": {
"@backstage/errors": "workspace:^",
"@microsoft/api-documenter": "^7.17.11",
"@microsoft/api-extractor": "^7.23.0",
"@microsoft/api-extractor-model": "^7.17.2",
"@microsoft/tsdoc": "0.14.1",
"chalk": "^4.0.0",
"commander": "^9.1.0",
"fs-extra": "10.1.0",
@@ -24,7 +24,7 @@ import {
dirname,
join,
} from 'path';
import { spawnSync, execFile } from 'child_process';
import { execFile } from 'child_process';
import prettier from 'prettier';
import fs from 'fs-extra';
import {
@@ -49,11 +49,17 @@ import {
import { DocTable } from '@microsoft/api-documenter/lib/nodes/DocTable';
import { DocTableRow } from '@microsoft/api-documenter/lib/nodes/DocTableRow';
import { DocHeading } from '@microsoft/api-documenter/lib/nodes/DocHeading';
import { CustomMarkdownEmitter } from '@microsoft/api-documenter/lib/markdown/CustomMarkdownEmitter';
import {
CustomMarkdownEmitter,
ICustomMarkdownEmitterOptions,
} from '@microsoft/api-documenter/lib/markdown/CustomMarkdownEmitter';
import { IMarkdownEmitterContext } from '@microsoft/api-documenter/lib/markdown/MarkdownEmitter';
import { AstDeclaration } from '@microsoft/api-extractor/lib/analyzer/AstDeclaration';
const tmpDir = resolvePath(process.cwd(), './node_modules/.cache/api-extractor');
const tmpDir = resolvePath(
process.cwd(),
'./node_modules/.cache/api-extractor',
);
/**
* All of this monkey patching below is because MUI has these bare package.json file as a method
@@ -99,7 +105,9 @@ function patchFileMessageFetcher(
} = router;
router.fetchAssociatedMessagesForReviewFile =
function patchedFetchAssociatedMessagesForReviewFile(ast) {
function patchedFetchAssociatedMessagesForReviewFile(
ast: AstDeclaration | undefined,
) {
const messages = fetchAssociatedMessagesForReviewFile.call(this, ast);
return transform(messages, ast);
};
@@ -113,7 +121,10 @@ function patchFileMessageFetcher(
const originalGenerateReviewFileContent =
ApiReportGenerator.generateReviewFileContent;
ApiReportGenerator.generateReviewFileContent =
function decoratedGenerateReviewFileContent(collector, ...moreArgs) {
function decoratedGenerateReviewFileContent(
collector: { program: Program; messageRouter: any },
...moreArgs: any[]
) {
const program = collector.program as Program;
// The purpose of this override is to allow the @ignore tag to be used to ignore warnings
@@ -137,7 +148,9 @@ ApiReportGenerator.generateReviewFileContent =
}
const [, symbolName] = symbolMatch;
const sourceFile = program.getSourceFile(message.sourceFilePath);
const sourceFile =
message.sourceFilePath &&
program.getSourceFile(message.sourceFilePath);
if (!sourceFile) {
throw new Error(
`Failed to find source file in program at path "${message.sourceFilePath}"`,
@@ -358,7 +371,10 @@ export async function runApiExtraction({
await fs.remove(outputDir);
const entryPoints = packageDirs.map(packageDir => {
return resolvePath(process.cwd(), `./dist-types/${packageDir}/src/index.d.ts`);
return resolvePath(
process.cwd(),
`./dist-types/${packageDir}/src/index.d.ts`,
);
});
let compilerState: CompilerState | undefined = undefined;
@@ -368,7 +384,11 @@ export async function runApiExtraction({
for (const packageDir of packageDirs) {
console.log(`## Processing ${packageDir}`);
const projectFolder = resolvePath(process.cwd(), packageDir);
const packageFolder = resolvePath(process.cwd(), './dist-types', packageDir);
const packageFolder = resolvePath(
process.cwd(),
'./dist-types',
packageDir,
);
const warningCountBefore = await countApiReportWarnings(projectFolder);
@@ -618,7 +638,7 @@ class ApiModelTransforms {
if (serialized.members.length !== 1) {
throw new Error(
`Unexpected members in serialized ApiPackage, [${serialized.members
.map(m => m.kind)
.map((m: { kind: any }) => m.kind)
.join(' ')}]`,
);
}
@@ -634,7 +654,7 @@ class ApiModelTransforms {
members: [
{
...entryPoint,
members: entryPoint.members.map(member =>
members: entryPoint.members.map((member: any) =>
transforms.reduce((m, t) => t(m), member),
),
},
@@ -847,7 +867,11 @@ export async function buildDocs({
}
/** @override */
emit(stringBuilder, docNode, options) {
emit(
stringBuilder: any,
docNode: DocNode,
options: ICustomMarkdownEmitterOptions,
) {
// Hack to get rid of the leading comment of each file, since
// we want the front matter to come first
stringBuilder._chunks.length = 0;
@@ -886,7 +910,7 @@ export async function buildDocs({
// so we hook in wherever we can. In this case we add the front matter
// just before writing the breadcrumbs at the top.
/** @override */
_writeBreadcrumb(output, apiItem) {
_writeBreadcrumb(output: any, apiItem: ApiItem & { name: string }) {
let title;
let description;
@@ -897,9 +921,12 @@ export async function buildDocs({
} else if (apiItem.kind === 'Model') {
title = 'Package Index';
description = 'Index of all Backstage Packages';
} else {
} else if (apiItem.name) {
title = apiItem.name;
description = `API Reference for ${apiItem.name}`;
} else {
title = apiItem.displayName;
description = `API Reference for ${apiItem.displayName}`;
}
// Add our front matter
@@ -925,7 +952,10 @@ export async function buildDocs({
};
}
_writeModelTable(output, apiModel): void {
_writeModelTable(
output: { appendNode: (arg0: DocTable | DocHeading) => void },
apiModel: { members: any },
): void {
const configuration = this._tsdocConfiguration;
const packagesTable = new DocTable({
@@ -998,7 +1028,10 @@ export async function buildDocs({
documenter.generateFiles();
}
export async function categorizePackageDirs(projectRoot, packageDirs) {
export async function categorizePackageDirs(
projectRoot: string,
packageDirs: any[],
) {
const dirs = packageDirs.slice();
const tsPackageDirs = new Array<string>();
const cliPackageDirs = new Array<string>();
@@ -1086,11 +1119,11 @@ function parseHelpPage(helpPageContent: string) {
// Trim away documentation
const sectionItems = sectionLines
.map(line => line.match(/^\s{1,8}(.*?)\s\s+/)?.[1])
.filter(Boolean);
.filter(Boolean) as string[];
if (sectionName.toLocaleLowerCase('en-US') === 'options:') {
if (sectionName?.toLocaleLowerCase('en-US') === 'options:') {
options = sectionItems;
} else if (sectionName.toLocaleLowerCase('en-US') === 'commands:') {
} else if (sectionName?.toLocaleLowerCase('en-US') === 'commands:') {
commands = sectionItems;
} else {
throw new Error(`Unknown CLI section: ${sectionName}`);
@@ -1250,96 +1283,3 @@ export async function runCliExtraction({
}
}
}
async function main() {
const projectRoot = resolvePath(process.cwd());
const isCiBuild = process.argv.includes('--ci');
const isDocsBuild = process.argv.includes('--docs');
const runTsc = process.argv.includes('--tsc');
const selectedPackageDirs = await findSpecificPackageDirs(
process.argv.slice(2).filter(arg => !arg.startsWith('--')),
);
if (selectedPackageDirs && isCiBuild) {
throw new Error(
'Package path arguments are not supported together with the --ci flag',
);
}
if (!selectedPackageDirs && !isCiBuild && !isDocsBuild) {
console.log('');
console.log(
'TIP: You can generate api-reports for select packages by passing package paths:',
);
console.log('');
console.log(
' yarn build:api-reports packages/config packages/core-plugin-api',
);
console.log('');
}
let temporaryTsConfigPath: string | undefined;
if (selectedPackageDirs) {
temporaryTsConfigPath = await createTemporaryTsConfig(selectedPackageDirs);
}
const tsconfigFilePath =
temporaryTsConfigPath ?? resolvePath(projectRoot, 'tsconfig.json');
if (runTsc) {
await fs.remove(resolvePath(projectRoot, 'dist-types'));
const { status } = spawnSync(
'yarn',
[
'tsc',
['--project', tsconfigFilePath],
['--skipLibCheck', 'false'],
['--incremental', 'false'],
].flat(),
{
stdio: 'inherit',
shell: true,
cwd: projectRoot,
},
);
if (status !== 0) {
process.exit(status);
}
}
const packageDirs = selectedPackageDirs ?? (await findPackageDirs());
const { tsPackageDirs, cliPackageDirs } = await categorizePackageDirs(
projectRoot,
packageDirs,
);
if (tsPackageDirs.length > 0) {
console.log('# Generating package API reports');
await runApiExtraction({
packageDirs: tsPackageDirs,
outputDir: tmpDir,
isLocalBuild: !isCiBuild,
tsconfigFilePath,
});
}
if (cliPackageDirs.length > 0) {
console.log('# Generating package CLI reports');
await runCliExtraction({
projectRoot,
packageDirs: cliPackageDirs,
isLocalBuild: !isCiBuild,
});
}
if (isDocsBuild) {
console.log('# Generating package documentation');
await buildDocs({
inputDir: tmpDir,
outputDir: resolvePath(projectRoot, 'docs/reference'),
});
}
}
main().catch(error => {
console.error(error.stack || String(error));
process.exit(1);
});
@@ -18,104 +18,105 @@ import { OptionValues } from 'commander';
import {resolve as resolvePath} from 'path';
import fs from 'fs-extra';
import { spawnSync } from 'child_process';
import {resolvePackagePath} from "@backstage/backend-common"
import {findSpecificPackageDirs, createTemporaryTsConfig, findPackageDirs, categorizePackageDirs, runApiExtraction, runCliExtraction, buildDocs} from './api-extractor';
import {
findSpecificPackageDirs,
createTemporaryTsConfig,
findPackageDirs,
categorizePackageDirs,
runApiExtraction,
runCliExtraction,
buildDocs,
} from './api-extractor';
export default async (paths:string[], opts: OptionValues ) => {
if(opts.ci){
process.stderr.write(
`hello ci`,
);
}
console.log(opts, paths)
process.stderr.write(
`hello `,
);
export default async (paths: string[], opts: OptionValues) => {
const tmpDir = resolvePath(
process.cwd(),
'./node_modules/.cache/api-extractor',
);
const projectRoot = resolvePath(process.cwd());
const isCiBuild = opts.ci;
const isDocsBuild = opts.docs;
const runTsc = opts.tsc;
const tmpDir = resolvePath('./node_modules/.cache/api-extractor');
const projectRoot = resolvePath(process.cwd());
console.log(`DIRNAME: ${__dirname}, ${projectRoot}`)
const isCiBuild = opts.ci;
const isDocsBuild = opts.docs;
const runTsc = opts.tsc;
const selectedPackageDirs = await findSpecificPackageDirs(paths
const selectedPackageDirs = await findSpecificPackageDirs(paths);
if (selectedPackageDirs && isCiBuild) {
throw new Error(
'Package path arguments are not supported together with the --ci flag',
);
if (selectedPackageDirs && isCiBuild) {
throw new Error(
'Package path arguments are not supported together with the --ci flag',
);
}
if (!selectedPackageDirs && !isCiBuild && !isDocsBuild) {
console.log('');
console.log(
'TIP: You can generate api-reports for select packages by passing package paths:',
);
console.log('');
console.log(
' yarn build:api-reports packages/config packages/core-plugin-api',
);
console.log('');
}
let temporaryTsConfigPath: string | undefined;
if (selectedPackageDirs) {
temporaryTsConfigPath = await createTemporaryTsConfig(selectedPackageDirs);
}
const tsconfigFilePath =
temporaryTsConfigPath ?? resolvePath(projectRoot, 'tsconfig.json');
if (runTsc) {
await fs.remove(resolvePath(projectRoot, 'dist-types'));
const { status } = spawnSync(
'yarn',
[
'tsc',
['--project', tsconfigFilePath],
['--skipLibCheck', 'false'],
['--incremental', 'false'],
].flat(),
{
stdio: 'inherit',
shell: true,
cwd: projectRoot,
},
);
if (status !== 0) {
process.exit(status || undefined);
}
if (!selectedPackageDirs && !isCiBuild && !isDocsBuild) {
console.log('');
console.log(
'TIP: You can generate api-reports for select packages by passing package paths:',
);
console.log('');
console.log(
' yarn build:api-reports packages/config packages/core-plugin-api',
);
console.log('');
}
let temporaryTsConfigPath: string | undefined;
if (selectedPackageDirs) {
temporaryTsConfigPath = await createTemporaryTsConfig(selectedPackageDirs);
}
const tsconfigFilePath =
temporaryTsConfigPath ?? resolvePath(projectRoot, 'tsconfig.json');
if (runTsc) {
await fs.remove(resolvePath(projectRoot, 'dist-types'));
const { status } = spawnSync(
'yarn',
[
'tsc',
['--project', tsconfigFilePath],
['--skipLibCheck', 'false'],
['--incremental', 'false'],
].flat(),
{
stdio: 'inherit',
shell: true,
cwd: projectRoot,
},
);
if (status !== 0) {
process.exit(status || undefined);
}
}
const packageDirs = selectedPackageDirs ?? (await findPackageDirs());
const { tsPackageDirs, cliPackageDirs } = await categorizePackageDirs(
}
const packageDirs = selectedPackageDirs ?? (await findPackageDirs());
const { tsPackageDirs, cliPackageDirs } = await categorizePackageDirs(
projectRoot,
packageDirs,
);
console.log({ tsPackageDirs, cliPackageDirs, isDocsBuild });
if (tsPackageDirs.length > 0) {
console.log('# Generating package API reports');
await runApiExtraction({
packageDirs: tsPackageDirs,
outputDir: tmpDir,
isLocalBuild: !isCiBuild,
tsconfigFilePath,
});
}
if (cliPackageDirs.length > 0) {
console.log('# Generating package CLI reports');
await runCliExtraction({
projectRoot,
packageDirs,
);
if (tsPackageDirs.length > 0) {
console.log('# Generating package API reports');
await runApiExtraction({
packageDirs: tsPackageDirs,
outputDir: tmpDir,
isLocalBuild: !isCiBuild,
tsconfigFilePath,
});
}
if (cliPackageDirs.length > 0) {
console.log('# Generating package CLI reports');
await runCliExtraction({
projectRoot,
packageDirs: cliPackageDirs,
isLocalBuild: !isCiBuild,
});
}
if (isDocsBuild) {
console.log('# Generating package documentation');
await buildDocs({
inputDir: tmpDir,
outputDir: resolvePath(projectRoot, 'docs/reference'),
});
}
packageDirs: cliPackageDirs,
isLocalBuild: !isCiBuild,
});
}
if (isDocsBuild) {
console.log('# Generating package documentation');
await buildDocs({
inputDir: tmpDir,
outputDir: resolvePath(projectRoot, 'docs/reference'),
});
}
};
+4 -11
View File
@@ -18,20 +18,13 @@ import { assertError } from '@backstage/errors';
import { Command } from 'commander';
import { exitWithError } from '../lib/errors';
const configOption = [
'--config <path>',
'Config files to load instead of app-config.yaml',
(opt: string, opts: string[]) => (opts ? [...opts, opt] : [opt]),
Array<string>(),
] as const;
export function registerCommands(program: Command) {
program
.command('api-reports [path...]')
.option('--ci', 'Do not require environment variables to be set')
.option('--tsc', 'Only validate the frontend configuration')
.option('--docs', 'Output deprecated configuration settings')
.description('Generate an API report for changed packages')
.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')
.description('Generate an API report for selected packages')
.action(
lazy(() => import('./api-reports/api-reports').then(m => m.default)),
);
@@ -1,15 +0,0 @@
/*
* 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.
*/
File diff suppressed because it is too large Load Diff
+4 -11
View File
@@ -7658,6 +7658,10 @@ __metadata:
resolution: "@backstage/repo-tools@workspace:packages/repo-tools"
dependencies:
"@backstage/errors": "workspace:^"
"@microsoft/api-documenter": ^7.17.11
"@microsoft/api-extractor": ^7.23.0
"@microsoft/api-extractor-model": ^7.17.2
"@microsoft/tsdoc": 0.14.1
chalk: ^4.0.0
commander: ^9.1.0
fs-extra: 10.1.0
@@ -10501,13 +10505,6 @@ __metadata:
languageName: node
linkType: hard
"@microsoft/tsdoc@npm:^0.14.1":
version: 0.14.2
resolution: "@microsoft/tsdoc@npm:0.14.2"
checksum: b167c89e916ba73ee20b9c9d5dba6aa3a0de25ed3d50050e8a344dca7cd43cb2e1059bd515c820369b6e708901dd3fda476a42bc643ca74a35671ce77f724a3a
languageName: node
linkType: hard
"@mswjs/cookies@npm:^0.2.0, @mswjs/cookies@npm:^0.2.2":
version: 0.2.2
resolution: "@mswjs/cookies@npm:0.2.2"
@@ -33071,10 +33068,6 @@ __metadata:
"@backstage/repo-tools": "workspace:*"
"@changesets/cli": ^2.14.0
"@manypkg/get-packages": ^1.1.3
"@microsoft/api-documenter": ^7.17.11
"@microsoft/api-extractor": ^7.23.0
"@microsoft/api-extractor-model": ^7.17.2
"@microsoft/tsdoc": ^0.14.1
"@octokit/rest": ^19.0.3
"@spotify/prettier-config": ^14.0.0
"@techdocs/cli": "workspace:*"