Files
cypress/scripts/changed-packages.js

144 lines
3.9 KiB
JavaScript

/* eslint-disable no-console */
const execa = require('execa')
const fs = require('fs')
const path = require('path')
// lists all packages that have changed from develop
// and all packages that depend on those
// some files that are intimately related to the binary exist outside of lerna packages
// so we want to make sure they're considered to be part of the binary
const containsBinaryOutsideLerna = (changedFiles) => {
const binaryFiles = [
'.node-version',
'circle.yml',
'electron-builder.json',
'package.json',
'yarn.lock',
]
return !!changedFiles.find((f) => f.includes('scripts/') || binaryFiles.includes(f))
}
// merges `cypress` and all binary packages prefixed with `@packages/`
// into a single `cypress` output
const convertPackagesToBinary = (packages) => {
let output = [...packages]
let includeBinary = false
output = output.filter((name) => {
const packageInBinary = name === 'cypress' || name.includes('@packages')
includeBinary = includeBinary || packageInBinary
return !packageInBinary
})
if (includeBinary) {
output.unshift('cypress')
}
return output
}
const getLernaPackages = async () => {
const { stdout } = await execa('npx', ['lerna', 'la', '--json'])
return JSON.parse(stdout)
}
// gets all files that have changed since the current branch diverged from some base branch
const getChangedFiles = async (base = 'origin/develop', output = false) => {
const { stdout: diff } = await execa('git', ['merge-base', base, 'HEAD'])
const { stdout: filesChanged } = await execa('git', ['diff', '--name-only', diff])
if (output) {
console.log(`Comparing against ${diff}`)
console.log(`Found the following changed files:`)
console.log(filesChanged)
}
return filesChanged.split('\n')
}
const getChangedPackages = async (base = 'origin/develop', output = false) => {
const { stdout: root } = await execa('git', ['rev-parse', '--show-toplevel'])
const packages = await getLernaPackages()
const files = await getChangedFiles(base, output)
// checks if a lerna package is changed
const isChanged = ({ location }) => {
const dir = path.relative(root, location)
return !!files.find((f) => f.includes(dir))
}
let changed = packages.filter(isChanged).map((p) => p.name)
changed = convertPackagesToBinary(changed)
if (!changed.includes('cypress') && containsBinaryOutsideLerna(files)) {
changed.unshift('cypress')
}
if (output) {
console.log()
console.log(`The following packages were changed:`)
console.log(changed.join('\n'))
}
return changed
}
// finds dependents as defined in the `ciDependents` field
// within the package.json of the package - see CONTRIBUTING.md for docs
const getPackageDependents = async (name) => {
const packages = await getLernaPackages()
const pack = packages.find((p) => p.name === name)
if (!pack) {
throw new Error('Could not find that package!')
}
const packageJson = JSON.parse(fs.readFileSync(path.join(pack.location, 'package.json')))
return packageJson['ciDependents'] || []
}
// gets all of the changed packages and their corresponding dependents
const getChangedPackagesAndDependents = async (base = 'origin/develop', output = false) => {
const changedPackages = await getChangedPackages(base, output)
const dependents = {}
for (const pack of changedPackages) {
dependents[pack] = await getPackageDependents(pack)
}
if (output) {
console.log()
console.log(`Changed packages and their dependents:`)
for (const pack in dependents) {
console.log(`${pack}: ${dependents[pack].join(', ') || 'none'}`)
}
}
return dependents
}
// execute main function if called from command line
if (require.main === module) {
const argv = require('minimist')(process.argv.slice(2))
const base = argv._[0]
getChangedPackagesAndDependents(base, true)
}
module.exports = {
getLernaPackages,
getChangedPackages,
getPackageDependents,
getChangedPackagesAndDependents,
}