diff --git a/.github/workflows/generate-test-seed.yml b/.github/workflows/generate-test-seed.yml index 1dd6d6ac..86f5edea 100644 --- a/.github/workflows/generate-test-seed.yml +++ b/.github/workflows/generate-test-seed.yml @@ -3,6 +3,7 @@ name: Generate Test Seed on: pull_request: paths: + - '.github/workflows/generate-test-seed.yml' - 'seed/seed.json' - 'studies/**' @@ -50,19 +51,16 @@ jobs: await comment(github, context, commentBody) - name: Install - run: | - npm ci + run: npm ci - - name: Build & Test - run: | - npm run typecheck:scripts - npm run build:proto - npm run typecheck - npm run test + - name: Typecheck + run: npm run typecheck - name: Lint - run: | - npm run lint -- --base "$BASE_SHA" + run: npm run lint -- --base "$BASE_SHA" + + - name: Test + run: npm run test - name: Generate seed run: | diff --git a/.github/workflows/test-src.yml b/.github/workflows/test-src.yml index 83681777..4e594933 100644 --- a/.github/workflows/test-src.yml +++ b/.github/workflows/test-src.yml @@ -7,26 +7,20 @@ on: jobs: build: runs-on: ubuntu-latest - env: - BASE_SHA: '${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha }}' - steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 - - name: fetch base commit - run: git fetch --depth=1 origin "$BASE_SHA" - - name: npm install run: npm install - - name: typecheck:scripts - run: npm run typecheck:scripts + - name: typecheck + run: npm run typecheck - - name: build - run: npm run build + - name: lint + run: npm run lint -- --all - name: run tests run: npm run test - - name: lint - run: npm run lint -- --base "$BASE_SHA" + - name: build + run: npm run build diff --git a/.prettierignore b/.prettierignore index d3e98286..496efcd9 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,3 +1,4 @@ seed/seed.json +src/proto/generated/* src/test/data/**/*unformatted* src/web/css/bootstrap.min.css diff --git a/src/scripts/lint.ts b/src/scripts/lint.ts index 8f2d01de..60074439 100644 --- a/src/scripts/lint.ts +++ b/src/scripts/lint.ts @@ -4,7 +4,7 @@ // You can obtain one at https://mozilla.org/MPL/2.0/. import { program } from '@commander-js/extra-typings'; -import { spawnSync } from 'child_process'; +import { execSync, spawnSync } from 'child_process'; // @ts-expect-error lint-staged is not typed. import lintStaged from 'lint-staged'; @@ -16,6 +16,7 @@ program 'types, and runs the corresponding linters. Use this command to ensure code\n' + 'quality before committing or pushing changes.', ) + .option('-a, --all', 'lint all files in the repository') .option('-b, --base ', 'base branch to compare against') .option('-s, --staged', 'use staged files instead of the branch diff') .option('-f, --fix', 'automatically fix problems') @@ -23,12 +24,49 @@ program .parse(); interface Options { + all?: true; base?: string; staged?: true; fix?: true; } async function main(options: Options) { + process.exitCode = options.all + ? lintAllFiles(options) + : await lintDiffFiles(options); +} + +// Returns an array of commands to lint all files. +function getLintAllCommands(options: Options): string[] { + return [ + 'prettier . --ignore-unknown' + (options.fix ? ' --write' : ' --check'), + 'eslint . --config src/.eslintrc.js' + (options.fix ? ' --fix' : ''), + // TODO(goodov): Add a command to lint JSON studies when per-file structure + // appears. + ]; +} + +// Returns a lint-staged configuration to lint modified files. +function getLintDiffCommands(options: Options): Record { + return { + '*': 'prettier --ignore-unknown' + (options.fix ? ' --write' : ' --check'), + '*.{ts,js,tsx,jsx}': + 'eslint --config src/.eslintrc.js' + (options.fix ? ' --fix' : ''), + 'studies/**/*.json': + 'npm run seed_tools -- check_study' + (options.fix ? ' --fix' : ''), + }; +} + +function lintAllFiles(options: Options): number { + for (const command of getLintAllCommands(options)) { + console.log(`Running: ${command}`); + execSync(command, { stdio: 'inherit' }); + } + + return 0; +} + +async function lintDiffFiles(options: Options): Promise { if (options.base !== undefined && options.staged) { console.error('The --base and --staged options are mutually exclusive'); process.exit(1); @@ -40,27 +78,12 @@ async function main(options: Options) { const passed: boolean = await lintStaged({ allowEmpty: false, concurrent: !options.fix, - config: createLintStagedConfig(options), + config: getLintDiffCommands(options), cwd: process.cwd(), diff: options.base !== undefined ? `${options.base}..HEAD` : undefined, }); - process.exitCode = passed ? 0 : 1; -} - -function createLintStagedConfig(options: Options): any { - const config: Record = { - '*': 'prettier --ignore-unknown' + (options.fix ? ' --write' : ' --check'), - 'studies/**/*.json': - 'npm run seed_tools -- check_study' + (options.fix ? ' --fix' : ''), - '*.{ts,js,tsx,jsx}': - 'eslint --config src/.eslintrc.js' + (options.fix ? ' --fix' : ''), - }; - - if (!options.fix) { - config['*.ts?(x)'] = () => 'npm run typecheck'; - } - return config; + return passed ? 0 : 1; } function isCurrentBranchAncestorOf(base: string): boolean {