diff --git a/.cspell.json b/.cspell.json index 1c88ffd414..c1aee5b1fe 100644 --- a/.cspell.json +++ b/.cspell.json @@ -15,6 +15,7 @@ "approveformyorg", "askar", "Askar", + "attw", "Authz", "authzn", "AWSSM", diff --git a/.github/workflows/are-the-types-wrong.yaml b/.github/workflows/are-the-types-wrong.yaml new file mode 100644 index 0000000000..852cb696fd --- /dev/null +++ b/.github/workflows/are-the-types-wrong.yaml @@ -0,0 +1,34 @@ +name: are-the-types-wrong-scan + +env: + NODEJS_VERSION: v18.18.2 + +on: + push: + # Publish `main` as Docker `latest` image. + branches: + - main + + # Publish `v1.2.3` tags as releases. + tags: + - v* + pull_request: + branches: + - main + +jobs: + scanning: + name: AreTheTypesWrong scan + runs-on: ubuntu-22.04 + steps: + - name: Set up NodeJS ${{ env.NODEJS_VERSION }} + uses: actions/setup-node@v4.0.3 + with: + node-version: ${{ env.NODEJS_VERSION }} + - uses: actions/checkout@v4.1.7 + - name: Installing AreTheTypesWrong Library + run: npm i -g @arethetypeswrong/cli + - run: npm run configure + - run: yarn lerna exec 'npm pack' + - name: Running AreTheTypesWrong scan + run: yarn run are-the-types-wrong diff --git a/package.json b/package.json index 149e9279b8..bdd9fe3cc2 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,7 @@ "format:prettier": "prettier --write --config .prettierrc.js \"./**/{openapi.json,*.ts,*.js}\"", "spellcheck": "cspell lint --no-progress \"*/*/src/**/*.{js,ts}\"", "tsc": "NODE_OPTIONS=\"--max_old_space_size=3072\" tsc --build --verbose", + "are-the-types-wrong": "TS_NODE_PROJECT=./tools/tsconfig.json node --trace-deprecation --experimental-modules --abort-on-uncaught-exception --loader ts-node/esm --experimental-specifier-resolution=node ./tools/custom-checks/run-attw-on-tgz.ts", "codegen": "run-s 'codegen:warmup-*' codegen:lerna codegen:cleanup", "codegen:cleanup": "rm --force --verbose ./openapitools.json", "codegen:lerna": "lerna run codegen", diff --git a/tools/custom-checks/get-all-tgz-path.ts b/tools/custom-checks/get-all-tgz-path.ts new file mode 100644 index 0000000000..8f6a6297fd --- /dev/null +++ b/tools/custom-checks/get-all-tgz-path.ts @@ -0,0 +1,49 @@ +import path from "path"; +import { fileURLToPath } from "url"; +import { globby, Options as GlobbyOptions } from "globby"; +import lernaCfg from "../../lerna.json" assert { type: "json" }; + +/** + * Interface for the response of the getAllTgzPath function. + * @property {Array} relativePaths - An array of relative paths to the + * package directories. + */ + +export interface IGetAllTgzPathResponse { + readonly relativePaths: Readonly>; +} + +/** + * Asynchronous function to get all tgz filepaths in a Lerna monorepo. + * @returns {Promise} A promise that resolves to an + * object containing the arrays of relative paths to the all tgz files. + */ + +export async function getAllTgzPath(): Promise { + const TAG = "[tools/get-all-tgz-path.ts]"; + const __filename = fileURLToPath(import.meta.url); + const __dirname = path.dirname(__filename); + const SCRIPT_DIR = __dirname; + const PROJECT_DIR = path.join(SCRIPT_DIR, "../../"); + + console.log(`${TAG} SCRIPT_DIR=${SCRIPT_DIR}`); + console.log(`${TAG} PROJECT_DIR=${PROJECT_DIR}`); + + const globbyOpts: GlobbyOptions = { + cwd: PROJECT_DIR, + onlyFiles: true, + expandDirectories: false, + ignore: ["**/node_modules"], + }; + + const tgzFilesPattern = lernaCfg.packages.map( + (pkg: string) => `${pkg}/**/hyperledger-*.tgz`, + ); + + const tgzFilesRelative = await globby(tgzFilesPattern, globbyOpts); + console.log("%s found %s tgz files.", TAG, tgzFilesRelative.length); + + return { + relativePaths: tgzFilesRelative, + }; +} diff --git a/tools/custom-checks/run-attw-on-tgz.ts b/tools/custom-checks/run-attw-on-tgz.ts new file mode 100644 index 0000000000..17a14f1b1f --- /dev/null +++ b/tools/custom-checks/run-attw-on-tgz.ts @@ -0,0 +1,46 @@ +import esMain from "es-main"; +import { getAllTgzPath } from "./get-all-tgz-path"; +import { exec } from "child_process"; +import { exit } from "process"; +import { promisify } from "node:util"; + +const execPromise = promisify(exec); + +export async function runAttwOnTgz(): Promise { + const TAG = "[tools/custom-checks/run-attw-on-tgz.ts]"; + console.log(`${TAG} Fetching .tgz file paths.`); + + const { relativePaths: tgzFilesRelative } = await getAllTgzPath(); + console.log(`${TAG} Found ${tgzFilesRelative.length} .tgz files.`); + + let attwFailedPackages: string[] = []; + + for (const filePath of tgzFilesRelative) { + try { + await execCommand("attw", filePath); + } catch { + attwFailedPackages.push(filePath); + } + } + + return attwFailedPackages; +} + +async function execCommand( + binaryName: string, + filePath: string, +): Promise { + const command = `${binaryName} ./${filePath}`; + const { stdout } = await execPromise(command); + console.log(stdout); +} + +if (esMain(import.meta)) { + const attwFailedPackages = await runAttwOnTgz(); + if (attwFailedPackages.length > 0) { + console.log("Types are wrong for these packages:"); + console.log(attwFailedPackages); + exit(1); + } + exit(0); +}