tfriem/svn-helper

View on GitHub
src/command-utils.ts

Summary

Maintainability
A
0 mins
Test Coverage
D
67%
import * as c from 'ansi-colors'
import * as fuzzy from 'fuzzy'
import * as indent from 'indent-string'
import * as inquirer from 'inquirer'
import * as Listr from 'listr'
import * as _ from 'lodash'

inquirer.registerPrompt('autocomplete', require('inquirer-autocomplete-prompt'))

import {
  BranchType,
  getBranchVersions,
  getTagVersions,
  getVersionFromWorkingCopy,
  SvnVersion,
  switchToVersion
} from './svn'

export function versionRequired(branchType: BranchType): boolean {
  return branchType !== BranchType.TRUNK
}

export async function askForVersion(
  path: string,
  type: BranchType
): Promise<string> {
  let versions: Array<string>
  if (type === BranchType.BRANCH) {
    versions = await getBranchVersions(path)
  } else if (type === BranchType.TAG) {
    versions = await getTagVersions(path)
  } else {
    throw Error('Trunk has no versions')
  }

  return ask('Version', versions)
}

export async function askForBranch(): Promise<string> {
  return ask('Branch', ['trunk', 'branches', 'tags'])
}

export async function ask(
  topic: string,
  options: Array<string>
): Promise<string> {
  const responses: {result: string} = await inquirer.prompt([
    {
      name: 'result',
      type: 'autocomplete',
      message: topic,
      // @ts-ignore
      source: async (_, input: string) => {
        input = input || ''
        return fuzzy.filter(input, options).map(res => res.original)
      }
    }
  ])

  return responses.result
}

export function getSvnBranchTypeFromString(branchType: string): BranchType {
  switch (branchType) {
    case 'trunk':
      return BranchType.TRUNK
    case 'branches':
      return BranchType.BRANCH
    case 'tags':
      return BranchType.TAG
    default:
      throw Error('Could not detect branch type')
  }
}

export function getSvnVersionFromConfig(versionString: string): SvnVersion {
  const [branch, version] = versionString.split('/')
  return new SvnVersion(getSvnBranchTypeFromString(branch), version)
}

export function svnVersionAsString(version: SvnVersion): string {
  switch (version.type) {
    case BranchType.TRUNK:
      return 'trunk'
    case BranchType.BRANCH:
      return `branches/${version.version}`
    case BranchType.TAG:
      return `tags/${version.version}`
  }
}

export function createSwitchTask(
  project: string,
  targetVersion: SvnVersion
): Listr.ListrTask {
  return {
    title: `Switch ${project} to ${svnVersionAsString(targetVersion)}`,
    task: async ctx => {
      const stdout = await switchToVersion(project, targetVersion)
      ctx.results.push({project, output: stdout})
    },
    skip: async () =>
      _.isEqual(await getVersionFromWorkingCopy(project), targetVersion)
  }
}

export async function runTasks(
  tasks: Array<Listr.ListrTask>,
  quiet: boolean,
  concurrency = 0
) {
  try {
    const concurrent = concurrency === 0 ? true : concurrency
    const context = await new Listr(tasks, {
      concurrent,
      exitOnError: false
    }).run({
      results: []
    })
    const results = context.results
    if (!quiet) {
      printResults(results)
    }
    return results
  } catch (err) {
    const results = err.context.results
    if (!quiet) {
      printResults(results)
    }

    err.errors.forEach((listError: ListrError) => {
      error('')
      error(`Command "${listError.cmd}" failed:`)
      error(indent(listError.stderr, 2))
    })
  }
}

export function info(message: string) {
  console.log(message)
}

export function warn(message: string) {
  console.log(c.yellow(message))
}

export function error(message: string) {
  console.log(c.red(message))
}

function printResults(results: Array<TaskResult>) {
  results.forEach(result => {
    info('')
    info(indent(`${result.project} (stdout):`, 2))
    info(indent(`${result.output}`, 4))
  })
}

interface TaskResult {
  project: string
  output: string
}

interface ListrError {
  cmd: string
  stdout: string
  stderr: string
  code: number
}