From c1cf014ca1e8aa76b0b5aeba6c000ef813118a9f Mon Sep 17 00:00:00 2001 From: Ben Irvin Date: Tue, 7 May 2024 17:17:46 +0200 Subject: [PATCH] chore: add test workflow * chore: add test workflow * chore: more cleanup --- .github/workflows/tests.yml | 60 +++++++++ package.json | 13 +- pnpm-lock.yaml | 109 +--------------- src/cli/commands/plugin/init/action.ts | 12 +- src/cli/commands/utils/helpers.ts | 168 +------------------------ 5 files changed, 73 insertions(+), 289 deletions(-) create mode 100644 .github/workflows/tests.yml diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..dae1b85 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,60 @@ +name: 'Tests' + +on: + push: + branches: + - main + pull_request: {} + +concurrency: + group: ${{ github.workflow }}-${{ github.ref_name }} + cancel-in-progress: true + +jobs: + lint-build: + name: 'lint & build' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v3 + - uses: actions/setup-node@v4 + with: + cache: pnpm + node-version: lts/* + - run: corepack enable && pnpm --version + - run: pnpm install + - run: pnpm lint + - run: pnpm prettier:check + - run: pnpm test:ts + - run: pnpm build + - uses: actions/upload-artifact@v3 + name: Cache build output + with: + name: build-output + path: | + bin/ + dist/ + +# test-unit: +# needs: 'lint-build' +# name: 'test:unit (${{ matrix.node }})' +# runs-on: ubuntu-latest +# strategy: +# # A test failing on windows doesn't mean it'll fail on macos. It's useful to let all tests run to its completion to get the full picture +# fail-fast: false +# matrix: +# node: [18, 20] +# steps: +# - uses: actions/checkout@v4 +# - uses: pnpm/action-setup@v3 +# - uses: actions/setup-node@v4 +# with: +# cache: pnpm +# node-version: ${{ matrix.node }} +# - run: corepack enable && pnpm --version +# - run: pnpm install +# - uses: actions/download-artifact@v3 +# name: Restore build output +# with: +# name: build-output +# - run: pnpm test:unit diff --git a/package.json b/package.json index 2bc9069..435a5fd 100644 --- a/package.json +++ b/package.json @@ -57,27 +57,18 @@ }, "dependencies": { "@strapi/pack-up": "5.0.0", - "@types/inquirer": "8.2.10", + "@types/prompts": "2.4.9", "boxen": "5.1.2", "chalk": "4.1.2", - "chokidar": "3.6.0", "commander": "8.3.0", "concurrently": "^8.2.2", - "esbuild": "0.20.2", - "esbuild-register": "3.5.0", - "fsevents": "^2.3.3", "get-latest-version": "5.1.0", "git-url-parse": "13.1.1", - "ini": "4.1.2", - "inquirer": "8.2.5", - "lodash": "4.17.21", "nodemon": "^3.1.0", "ora": "5.4.1", "outdent": "0.8.0", "pkg-up": "3.1.0", "prettier": "2.8.8", - "prettier-plugin-packagejson": "2.4.14", - "prompts": "2.4.2", "typescript": "5.4.4", "yup": "0.32.9" }, @@ -90,11 +81,9 @@ "@swc/core": "^1.4.13", "@swc/jest": "^0.2.36", "@types/git-url-parse": "9.0.3", - "@types/ini": "4.1.0", "@types/jest": "^29.5.12", "@types/nodemon": "^1.19.6", "@types/prettier": "^2.0.0", - "@types/prompts": "2.4.9", "@typescript-eslint/eslint-plugin": "^7.6.0", "@typescript-eslint/parser": "^7.6.0", "eslint": "^8.56.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 397bb4e..2fe39a6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,48 +11,27 @@ importers: '@strapi/pack-up': specifier: 5.0.0 version: 5.0.0(@types/node@20.12.6) - '@types/inquirer': - specifier: 8.2.10 - version: 8.2.10 + '@types/prompts': + specifier: 2.4.9 + version: 2.4.9 boxen: specifier: 5.1.2 version: 5.1.2 chalk: specifier: 4.1.2 version: 4.1.2 - chokidar: - specifier: 3.6.0 - version: 3.6.0 commander: specifier: 8.3.0 version: 8.3.0 concurrently: specifier: ^8.2.2 version: 8.2.2 - esbuild: - specifier: 0.20.2 - version: 0.20.2 - esbuild-register: - specifier: 3.5.0 - version: 3.5.0(esbuild@0.20.2) - fsevents: - specifier: ^2.3.3 - version: 2.3.3 get-latest-version: specifier: 5.1.0 version: 5.1.0 git-url-parse: specifier: 13.1.1 version: 13.1.1 - ini: - specifier: 4.1.2 - version: 4.1.2 - inquirer: - specifier: 8.2.5 - version: 8.2.5 - lodash: - specifier: 4.17.21 - version: 4.17.21 nodemon: specifier: ^3.1.0 version: 3.1.0 @@ -68,12 +47,6 @@ importers: prettier: specifier: 2.8.8 version: 2.8.8 - prettier-plugin-packagejson: - specifier: 2.4.14 - version: 2.4.14(prettier@2.8.8) - prompts: - specifier: 2.4.2 - version: 2.4.2 typescript: specifier: 5.4.4 version: 5.4.4 @@ -105,9 +78,6 @@ importers: '@types/git-url-parse': specifier: 9.0.3 version: 9.0.3 - '@types/ini': - specifier: 4.1.0 - version: 4.1.0 '@types/jest': specifier: ^29.5.12 version: 29.5.12 @@ -117,9 +87,6 @@ importers: '@types/prettier': specifier: ^2.0.0 version: 2.7.3 - '@types/prompts': - specifier: 2.4.9 - version: 2.4.9 '@typescript-eslint/eslint-plugin': specifier: ^7.6.0 version: 7.6.0(@typescript-eslint/parser@7.6.0(eslint@8.56.0)(typescript@5.4.4))(eslint@8.56.0)(typescript@5.4.4) @@ -964,12 +931,6 @@ packages: '@types/graceful-fs@4.1.9': resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} - '@types/ini@4.1.0': - resolution: {integrity: sha512-mTehMtc+xtnWBBvqizcqYCktKDBH2WChvx1GU3Sfe4PysFDXiNe+1YwtpVX1MDtCa4NQrSPw2+3HmvXHY3gt1w==} - - '@types/inquirer@8.2.10': - resolution: {integrity: sha512-IdD5NmHyVjWM8SHWo/kPBgtzXatwPkfwzyP3fN1jF2g9BWt5WO+8hL2F4o2GKIYsU40PpqeevuUWvkS/roXJkA==} - '@types/istanbul-lib-coverage@2.0.6': resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} @@ -1018,9 +979,6 @@ packages: '@types/stack-utils@2.0.3': resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} - '@types/through@0.0.33': - resolution: {integrity: sha512-HsJ+z3QuETzP3cswwtzt2vEIiHBk/dCcHGhbmG5X3ecnwFD/lPrMpliGXxSCg03L9AhrdwA4Oz/qfspkDW+xGQ==} - '@types/yargs-parser@21.0.3': resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} @@ -1453,10 +1411,6 @@ packages: resolution: {integrity: sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==} engines: {node: '>=18'} - cli-width@3.0.0: - resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==} - engines: {node: '>= 10'} - cliui@6.0.0: resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} @@ -2059,10 +2013,6 @@ packages: fb-watchman@2.0.2: resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} - figures@3.2.0: - resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} - engines: {node: '>=8'} - file-entry-cache@6.0.1: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} @@ -2353,10 +2303,6 @@ packages: resolution: {integrity: sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - inquirer@8.2.5: - resolution: {integrity: sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==} - engines: {node: '>=12.0.0'} - internal-slot@1.0.7: resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} engines: {node: '>= 0.4'} @@ -2962,9 +2908,6 @@ packages: ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - mute-stream@0.0.8: - resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} - nanoclone@0.2.1: resolution: {integrity: sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA==} @@ -3409,10 +3352,6 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true - run-async@2.4.1: - resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==} - engines: {node: '>=0.12.0'} - run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} @@ -5041,13 +4980,6 @@ snapshots: dependencies: '@types/node': 20.12.6 - '@types/ini@4.1.0': {} - - '@types/inquirer@8.2.10': - dependencies: - '@types/through': 0.0.33 - rxjs: 7.8.1 - '@types/istanbul-lib-coverage@2.0.6': {} '@types/istanbul-lib-report@3.0.3': @@ -5094,10 +5026,6 @@ snapshots: '@types/stack-utils@2.0.3': {} - '@types/through@0.0.33': - dependencies: - '@types/node': 20.12.6 - '@types/yargs-parser@21.0.3': {} '@types/yargs@17.0.32': @@ -5670,8 +5598,6 @@ snapshots: slice-ansi: 5.0.0 string-width: 7.1.0 - cli-width@3.0.0: {} - cliui@6.0.0: dependencies: string-width: 4.2.3 @@ -6523,10 +6449,6 @@ snapshots: dependencies: bser: 2.1.1 - figures@3.2.0: - dependencies: - escape-string-regexp: 1.0.5 - file-entry-cache@6.0.1: dependencies: flat-cache: 3.2.0 @@ -6595,7 +6517,8 @@ snapshots: fs.realpath@1.0.0: {} - fsevents@2.3.3: {} + fsevents@2.3.3: + optional: true function-bind@1.1.2: {} @@ -6814,24 +6737,6 @@ snapshots: ini@4.1.2: {} - inquirer@8.2.5: - dependencies: - ansi-escapes: 4.3.2 - chalk: 4.1.2 - cli-cursor: 3.1.0 - cli-width: 3.0.0 - external-editor: 3.1.0 - figures: 3.2.0 - lodash: 4.17.21 - mute-stream: 0.0.8 - ora: 5.4.1 - run-async: 2.4.1 - rxjs: 7.8.1 - string-width: 4.2.3 - strip-ansi: 6.0.1 - through: 2.3.8 - wrap-ansi: 7.0.0 - internal-slot@1.0.7: dependencies: es-errors: 1.3.0 @@ -7591,8 +7496,6 @@ snapshots: ms@2.1.2: {} - mute-stream@0.0.8: {} - nanoclone@0.2.1: {} nanoid@3.3.7: {} @@ -8056,8 +7959,6 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.14.1 fsevents: 2.3.3 - run-async@2.4.1: {} - run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 diff --git a/src/cli/commands/plugin/init/action.ts b/src/cli/commands/plugin/init/action.ts index 7598d72..bc305cb 100644 --- a/src/cli/commands/plugin/init/action.ts +++ b/src/cli/commands/plugin/init/action.ts @@ -112,13 +112,13 @@ const PLUGIN_TEMPLATE = defineTemplate(async ({ logger, gitConfig, packagePath } name: 'repo', type: 'text', message: 'git url', - validate(v) { - if (!v) { + validate(val: unknown) { + if (!val) { return true; } try { - const result = gitUrlParse(v); + const result = gitUrlParse(val as any); repo = { source: result.source, owner: result.owner, name: result.name }; @@ -133,12 +133,12 @@ const PLUGIN_TEMPLATE = defineTemplate(async ({ logger, gitConfig, packagePath } type: 'text', message: 'plugin name', initial: () => repo?.name ?? '', - validate(v) { - if (!v) { + validate(val: unknown) { + if (!val || typeof val !== 'string') { return 'package name is required'; } - const match = PACKAGE_NAME_REGEXP.exec(v); + const match = PACKAGE_NAME_REGEXP.exec(val); if (!match) { return 'invalid package name'; diff --git a/src/cli/commands/utils/helpers.ts b/src/cli/commands/utils/helpers.ts index 5d9848c..3edfdc5 100644 --- a/src/cli/commands/utils/helpers.ts +++ b/src/cli/commands/utils/helpers.ts @@ -1,119 +1,4 @@ -/* eslint-disable @typescript-eslint/no-var-requires */ -import boxen from 'boxen'; -import chalk from 'chalk'; -import { prompt } from 'inquirer'; -import { isString, isArray } from 'lodash/fp'; - import type { CLIContext } from '../../../types'; -import type { Command } from 'commander'; - -/** - * Helper functions for the Strapi CLI - */ -const bytesPerKb = 1024; -const sizes = ['B ', 'KB', 'MB', 'GB', 'TB', 'PB'] as const; - -/** - * Convert bytes to a human readable formatted string, for example "1024" becomes "1KB" - */ -const readableBytes = (bytes: number, decimals = 1, padStart = 0) => { - if (!bytes) { - return '0'; - } - const i = Math.floor(Math.log(bytes) / Math.log(bytesPerKb)); - const size = sizes[i]; - - if (!size) { - throw new Error('invalid size'); - } - - const result = `${parseFloat((bytes / bytesPerKb ** i).toFixed(decimals))} ${size.padStart(2)}`; - - return result.padStart(padStart); -}; - -interface ExitWithOptions { - logger?: Console; - prc?: NodeJS.Process; -} - -/** - * - * Display message(s) to console and then call process.exit with code. - * If code is zero, console.log and green text is used for messages, otherwise console.error and red text. - * - */ -const exitWith = (code: number, message?: string | string[], options: ExitWithOptions = {}) => { - const { logger = console, prc = process } = options; - - const log = (msg: string) => { - if (code === 0) { - logger.log(chalk.green(msg)); - } else { - logger.error(chalk.red(msg)); - } - }; - - if (isString(message)) { - log(message); - } else if (isArray(message)) { - message.forEach((msg) => log(msg)); - } - - prc.exit(code); -}; - -/** - * assert that a URL object has a protocol value - * - */ -const assertUrlHasProtocol = (url: URL, protocols?: string | string[]) => { - if (!url.protocol) { - exitWith(1, `${url.toString()} does not have a protocol`); - } - - // if just checking for the existence of a protocol, return - if (!protocols) { - return; - } - - if (isString(protocols)) { - if (protocols !== url.protocol) { - exitWith(1, `${url.toString()} must have the protocol ${protocols}`); - } - return; - } - - // assume an array - if (!protocols.some((protocol) => url.protocol === protocol)) { - return exitWith( - 1, - `${url.toString()} must have one of the following protocols: ${protocols.join(',')}` - ); - } -}; - -type ConditionCallback = (opts: Record) => Promise; -type IsMetCallback = (command: Command) => Promise; -type IsNotMetCallback = (command: Command) => Promise; - -/** - * Passes commander options to conditionCallback(). If it returns true, call isMetCallback otherwise call isNotMetCallback - */ -const ifOptions = ( - conditionCallback: ConditionCallback, - isMetCallback: IsMetCallback = async () => {}, - isNotMetCallback: IsNotMetCallback = async () => {} -) => { - return async (command: Command) => { - const opts = command.opts(); - if (await conditionCallback(opts)) { - await isMetCallback(command); - } else { - await isNotMetCallback(command); - } - }; -}; const runAction = (name: string, action: (...args: any[]) => Promise) => @@ -129,55 +14,4 @@ const runAction = }); }; -/** - * @description Notify users this is an experimental command and get them to approve first - * this can be opted out by passing `yes` as a property of the args object. - * - * @example - * ```ts - * const { notifyExperimentalCommand } = require('../utils/helpers'); - * - * const myCommand = async ({ force }) => { - * await notifyExperimentalCommand('plugin:build', { force }); - * } - * ``` - */ -const notifyExperimentalCommand = async (name: string, { force }: { force?: boolean } = {}) => { - // eslint-disable-next-line no-console - console.log( - boxen( - `The ${chalk.bold( - chalk.underline(name) - )} command is considered experimental, use at your own risk.`, - { - title: 'Warning', - padding: 1, - margin: 1, - align: 'center', - borderColor: 'yellow', - borderStyle: 'bold', - } - ) - ); - - if (!force) { - const { confirmed } = await prompt({ - type: 'confirm', - name: 'confirmed', - message: 'Do you want to continue?', - }); - - if (!confirmed) { - process.exit(0); - } - } -}; - -export { - exitWith, - assertUrlHasProtocol, - ifOptions, - readableBytes, - runAction, - notifyExperimentalCommand, -}; +export { runAction };