NaturalCycles/dev-lib

View on GitHub
src/cmd/lint-all.command.ts

Summary

Maintainability
A
1 hr
Test Coverage
F
0%
import { execSync } from 'node:child_process'
import fs from 'node:fs'
import { _since, _truncate } from '@naturalcycles/js-lib'
import {
  boldGrey,
  dimGrey,
  commitMessageToTitleMessage,
  getLastGitCommitMsg,
  gitCommitAll,
  gitHasUncommittedChanges,
  gitPull,
  gitPush,
  execVoidCommandSync,
} from '@naturalcycles/nodejs-lib'
import yargs from 'yargs'
import { runPrettier } from '../util/prettier.util'
import { stylelintAll } from '../util/stylelint.util'
import { eslintAllCommand } from './eslint-all.command'

/**
 * Run all linters.
 */
export async function lintAllCommand(): Promise<void> {
  const started = Date.now()
  const { commitOnChanges, failOnChanges } = yargs.options({
    commitOnChanges: {
      type: 'boolean',
      default: false,
    },
    failOnChanges: {
      type: 'boolean',
      default: false,
    },
  }).argv

  const hadChangesBefore = gitHasUncommittedChanges()

  // We run eslint BEFORE Prettier, because eslint can delete e.g unused imports.
  await eslintAllCommand()

  if (
    fs.existsSync(`node_modules/stylelint`) &&
    fs.existsSync(`node_modules/stylelint-config-standard-scss`)
  ) {
    stylelintAll()
  }

  runPrettier()

  runActionLint()

  await runKTLint()

  console.log(`${boldGrey('lint-all')} ${dimGrey(`took ` + _since(started))}`)

  if (commitOnChanges || failOnChanges) {
    // detect changes
    const hasChanges = gitHasUncommittedChanges()
    if (hasChanges) {
      if (hadChangesBefore) {
        console.log(`lint-all: there are changes before running lint-all, will not commit`)
      } else {
        const msg =
          'style(ci): ' + _truncate(commitMessageToTitleMessage(getLastGitCommitMsg()), 60)

        // pull, commit, push changes
        gitPull()
        gitCommitAll(msg)
        gitPush()
      }

      // fail on changes
      if (failOnChanges) {
        console.log('lint-all failOnChanges: exiting with status 1')
        process.exitCode = 1
      }
    }
  }
}

async function runKTLint(): Promise<void> {
  if (fs.existsSync(`node_modules/@naturalcycles/ktlint`)) {
    const ktlintLib = require('@naturalcycles/ktlint')
    await ktlintLib.ktlintAll()
  }
}

function runActionLint(): void {
  // Only run if there is a folder of `.github/workflows`, otherwise actionlint will fail
  if (!fs.existsSync('.github/workflows')) return

  if (canRunBinary('actionlint')) {
    const started = Date.now()
    execVoidCommandSync(`actionlint`)
    console.log(`${boldGrey('actionlint')} ${dimGrey(`took ` + _since(started))}`)
  } else {
    console.log(
      `actionlint is not installed and won't be run.\nThis is how to install it: https://github.com/rhysd/actionlint/blob/main/docs/install.md`,
    )
  }
}

function canRunBinary(name: string): boolean {
  try {
    execSync(`which ${name}`)
    return true
  } catch {
    return false
  }
}