diff --git a/.github/actions/check-public-api/action.yml b/.github/actions/check-public-api/action.yml index 200e36c005..9750c2b184 100644 --- a/.github/actions/check-public-api/action.yml +++ b/.github/actions/check-public-api/action.yml @@ -6,8 +6,8 @@ inputs: default: 'false' excluded_packages: description: 'Packages to exclude when checking the public API.' - ignored_paths: - description: 'Paths to ignore when checking the public API.' + ignored_path_pattern: + description: 'Regular expression for paths to be ignore when checking the public API.' runs: using: 'node20' diff --git a/.github/actions/check-public-api/index.js b/.github/actions/check-public-api/index.js index b18547ae85..34181c53d5 100644 --- a/.github/actions/check-public-api/index.js +++ b/.github/actions/check-public-api/index.js @@ -30,20 +30,22 @@ const mock_fs_1 = __importDefault(__nccwpck_require__(55850)); const internal_1 = __nccwpck_require__(81583); const get_packages_1 = __nccwpck_require__(30886); const { readFile, lstat, readdir } = fs_1.promises; -const localConfigPath = (0, path_1.join)(process.cwd(), 'build-packages/check-public-api/local-config.json'); const pathToTsConfigRoot = (0, path_1.join)(process.cwd(), 'tsconfig.json'); const pathRootNodeModules = (0, path_1.join)(process.cwd(), 'node_modules'); exports.regexExportedIndex = /export(?:type)?\{([\w,]+)\}from'\./g; exports.regexExportedInternal = /\.\/([\w-]+)/g; function paths(pathToPackage) { return { - pathToSource: (0, path_1.join)(pathToPackage, 'src'), - pathToPackageJson: (0, path_1.join)(pathToPackage, 'package.json'), - pathToTsConfig: (0, path_1.join)(pathToPackage, 'tsconfig.json'), - pathToNodeModules: (0, path_1.join)(pathToPackage, 'node_modules'), + pathToSource: getPathWithPosixSeparator((0, path_1.join)(pathToPackage, 'src')), + pathToPackageJson: getPathWithPosixSeparator((0, path_1.join)(pathToPackage, 'package.json')), + pathToTsConfig: getPathWithPosixSeparator((0, path_1.join)(pathToPackage, 'tsconfig.json')), + pathToNodeModules: getPathWithPosixSeparator((0, path_1.join)(pathToPackage, 'node_modules')), pathCompiled: 'dist' }; } +function getPathWithPosixSeparator(filePath) { + return filePath.split(path_1.sep).join(path_1.posix.sep); +} function mockFileSystem(pathToPackage) { const { pathToSource, pathToTsConfig, pathToNodeModules, pathToPackageJson } = paths(pathToPackage); (0, mock_fs_1.default)({ @@ -84,11 +86,11 @@ function getListFromInput(inputKey) { */ function compareApisAndLog(allExportedIndex, allExportedTypes) { let setsAreEqual = true; - const ignoredPaths = getListFromInput('ignored_paths'); + const ignoredPathPattern = (0, core_1.getInput)('ignored_path_pattern'); allExportedTypes.forEach(exportedType => { - const normalizedPath = exportedType.path.split(path_1.sep).join(path_1.posix.sep); - const isPathMatched = ignoredPaths.length - ? ignoredPaths.some(ignoredPath => normalizedPath.includes(ignoredPath.split(path_1.sep).join(path_1.posix.sep))) + const normalizedPath = getPathWithPosixSeparator(exportedType.path); + const isPathMatched = ignoredPathPattern + ? new RegExp(ignoredPathPattern).test(normalizedPath) : false; if (!allExportedIndex.find(nameInIndex => exportedType.name === nameInIndex)) { if (isPathMatched) { @@ -128,7 +130,10 @@ async function checkApiOfPackage(pathToPackage) { prettierOptions: internal_1.defaultPrettierConfig, usePrettier: false } - }, { exclude: includeExclude?.exclude, include: ['**/*.ts'] }); + }, { + exclude: includeExclude ? includeExclude.exclude : [], + include: ['**/*.ts'] + }); const forceInternalExports = (0, core_1.getInput)('force_internal_exports') === 'true'; if (forceInternalExports) { await checkBarrelRecursive(pathToSource); @@ -232,12 +237,12 @@ async function parseIndexFile(filePath, forceInternalExports) { ...parseBarrelFile(fileContent, exports.regexExportedIndex), ...parseExportedObjectsInFile(fileContent).map(obj => obj.name) ]; - const starFiles = captureGroupsFromGlobalRegex(/export \* from '([\w\/.-]+)'/g, fileContent); + const starFiles = captureGroupsFromGlobalRegex(/export \* from '([\w/.-]+)'/g, fileContent); const starFileExports = await Promise.all(starFiles.map(async (relativeFilePath) => { - const filePath = relativeFilePath.endsWith('.js') + const absolutePath = relativeFilePath.endsWith('.js') ? (0, path_1.resolve)(cwd, `${relativeFilePath.slice(0, -3)}.ts`) : (0, path_1.resolve)(cwd, `${relativeFilePath}.ts`); - return parseIndexFile(filePath, forceInternalExports); + return parseIndexFile(absolutePath, forceInternalExports); })); return [...localExports, ...starFileExports.flat()]; } @@ -294,8 +299,8 @@ async function runCheckApi() { try { await checkApiOfPackage(pkg.dir); } - catch (error) { - (0, core_1.setFailed)(`API check failed for ${pkg.relativeDir}: ${error}`); + catch (e) { + (0, core_1.setFailed)(`API check failed for ${pkg.relativeDir}: ${e}`); process.exit(1); } } diff --git a/build-packages/check-public-api/index.ts b/build-packages/check-public-api/index.ts index 032325212f..820a5e8f60 100644 --- a/build-packages/check-public-api/index.ts +++ b/build-packages/check-public-api/index.ts @@ -1,14 +1,6 @@ /* eslint-disable jsdoc/require-jsdoc */ -import path, { - join, - resolve, - parse, - basename, - dirname, - posix, - sep -} from 'path'; +import { join, resolve, parse, basename, dirname, posix, sep } from 'path'; import { promises, existsSync } from 'fs'; import { glob } from 'glob'; import { info, warning, error, getInput, setFailed } from '@actions/core'; @@ -20,15 +12,11 @@ import { readIncludeExcludeWithDefaults, transpileDirectory } from '@sap-cloud-sdk/generator-common/internal'; -import type { CompilerOptions } from 'typescript'; import { getPackages } from '@manypkg/get-packages'; +import type { CompilerOptions } from 'typescript'; const { readFile, lstat, readdir } = promises; -const localConfigPath = join( - process.cwd(), - 'build-packages/check-public-api/local-config.json' -); const pathToTsConfigRoot = join(process.cwd(), 'tsconfig.json'); const pathRootNodeModules = join(process.cwd(), 'node_modules'); export const regexExportedIndex = /export(?:type)?\{([\w,]+)\}from'\./g; @@ -48,14 +36,24 @@ function paths(pathToPackage: string): { pathCompiled: string; } { return { - pathToSource: join(pathToPackage, 'src'), - pathToPackageJson: join(pathToPackage, 'package.json'), - pathToTsConfig: join(pathToPackage, 'tsconfig.json'), - pathToNodeModules: join(pathToPackage, 'node_modules'), + pathToSource: getPathWithPosixSeparator(join(pathToPackage, 'src')), + pathToPackageJson: getPathWithPosixSeparator( + join(pathToPackage, 'package.json') + ), + pathToTsConfig: getPathWithPosixSeparator( + join(pathToPackage, 'tsconfig.json') + ), + pathToNodeModules: getPathWithPosixSeparator( + join(pathToPackage, 'node_modules') + ), pathCompiled: 'dist' }; } +function getPathWithPosixSeparator(filePath: string): string { + return filePath.split(sep).join(posix.sep); +} + function mockFileSystem(pathToPackage: string) { const { pathToSource, pathToTsConfig, pathToNodeModules, pathToPackageJson } = paths(pathToPackage); @@ -105,15 +103,13 @@ function compareApisAndLog( allExportedTypes: ExportedObject[] ): boolean { let setsAreEqual = true; - const ignoredPaths = getListFromInput('ignored_paths'); + const ignoredPathPattern = getInput('ignored_path_pattern'); allExportedTypes.forEach(exportedType => { - const normalizedPath = exportedType.path.split(sep).join(posix.sep); + const normalizedPath = getPathWithPosixSeparator(exportedType.path); - const isPathMatched = ignoredPaths.length - ? ignoredPaths.some(ignoredPath => - normalizedPath.includes(ignoredPath.split(sep).join(posix.sep)) - ) + const isPathMatched = ignoredPathPattern + ? new RegExp(ignoredPathPattern).test(normalizedPath) : false; if ( !allExportedIndex.find(nameInIndex => exportedType.name === nameInIndex) @@ -169,7 +165,10 @@ export async function checkApiOfPackage(pathToPackage: string): Promise { usePrettier: false } }, - { exclude: includeExclude?.exclude!, include: ['**/*.ts'] } + { + exclude: includeExclude ? includeExclude.exclude : [], + include: ['**/*.ts'] + } ); const forceInternalExports = getInput('force_internal_exports') === 'true'; @@ -309,16 +308,16 @@ export async function parseIndexFile( ...parseExportedObjectsInFile(fileContent).map(obj => obj.name) ]; const starFiles = captureGroupsFromGlobalRegex( - /export \* from '([\w\/.-]+)'/g, + /export \* from '([\w/.-]+)'/g, fileContent ); const starFileExports = await Promise.all( starFiles.map(async relativeFilePath => { - const filePath = relativeFilePath.endsWith('.js') + const absolutePath = relativeFilePath.endsWith('.js') ? resolve(cwd, `${relativeFilePath.slice(0, -3)}.ts`) : resolve(cwd, `${relativeFilePath}.ts`); - return parseIndexFile(filePath, forceInternalExports); + return parseIndexFile(absolutePath, forceInternalExports); }) ); return [...localExports, ...starFileExports.flat()]; @@ -410,8 +409,8 @@ async function runCheckApi() { for (const pkg of packagesToCheck) { try { await checkApiOfPackage(pkg.dir); - } catch (error) { - setFailed(`API check failed for ${pkg.relativeDir}: ${error}`); + } catch (e) { + setFailed(`API check failed for ${pkg.relativeDir}: ${e}`); process.exit(1); } }