blob: 65c92bc721671bfaadb3c5e158bdd7213d250136 [file] [log] [blame]
#!/usr/bin/env node
// usage: flow-coverage
//
// Run flow coverage on project.
const childProcess = require('child_process')
const flow = require('flow-bin')
const fs = require('fs')
const {join} = require('path')
const execFile = (file, args) =>
new Promise((resolve, reject) => {
childProcess.execFile(
file,
args,
{
maxBuffer: Infinity
},
(error, stdout, stderr) => {
if (error) {
reject(error)
} else {
resolve({stdout, stderr})
}
}
)
})
async function execFileJSON(file, args) {
args.push('--json')
const {stdout, stderr} = await execFile(file, args)
if (stderr) {
return JSON.parse(stderr)
} else {
return JSON.parse(stdout)
}
}
function computeCoverage(covered, uncovered) {
const total = covered + uncovered
if (total) {
return 100 * (covered / total)
} else {
return 100
}
}
async function getCoverage(path) {
const json = await execFileJSON(flow, ['coverage', path])
if (json && json.expressions) {
const uncoveredCount = json.expressions['uncovered_count']
const coveredCount = json.expressions['covered_count']
const covered = computeCoverage(coveredCount, uncoveredCount)
return {path, uncoveredCount, coveredCount, covered}
} else {
return {path, uncoveredCount: 0, coveredCount: 0, covered: 0}
}
}
async function startFlow() {
try {
await execFile(flow, ['start', '--wait'])
} catch (error) {
if (error.code === 11) {
/* already running */
} else {
throw error
}
}
}
// const ignore = [/\.flowconfig$/, /\.json$/, /\.test\.js$/, /\/__generated__\//, /\/flow-typed\//, /\/node_modules\//]
//
// async function flowList() {
// execFile('git', ['grep', '--name-only', '--', '@flow'])
//
// const paths = await execFileJSON(flow, ['ls'])
// return paths.filter(path => !ignore.some(re => re.test(path)))
// }
async function grepFlowFiles() {
const {stdout} = await execFile('git', ['grep', '--null', '--name-only', '--', '@flow'])
return stdout.split('\0').filter(path => path)
}
;(async function() {
let threshold = 0
const packageJsonPath = join(process.cwd(), 'package.json')
if (fs.existsSync(packageJsonPath)) {
const packageJson = require(packageJsonPath)
threshold = (packageJson.flow && packageJson.flow.coverageThreshold) || 0
}
await startFlow()
const files = await grepFlowFiles()
let totalCoveredCount = 0
let totalUncoveredCount = 0
for (const file of files) {
const {path, covered, coveredCount, uncoveredCount} = await getCoverage(file)
process.stdout.write(`${covered.toFixed()}\t${path}\n`)
totalCoveredCount += coveredCount
totalUncoveredCount += uncoveredCount
}
const totalCoverage = computeCoverage(totalCoveredCount, totalUncoveredCount)
process.stdout.write(`${totalCoverage.toFixed()}\t(total)\n`)
if (totalCoverage < threshold) {
process.stderr.write(`expected at least ${threshold}% coverage, but was ${totalCoverage.toFixed()}%\n`)
process.exit(1)
}
})().catch(error => {
process.stderr.write(`${error}\n`)
process.exit(2)
})