mira
Version:
NearForm Accelerator for Cloud Native Serverless AWS
193 lines (182 loc) • 7.99 kB
text/typescript
import chalk from 'chalk'
import fs from 'fs'
import FileHelpers from './filehelpers'
// eslint-disable-next-line
const minimist = require("minimist");
const args = minimist(process.argv.slice(2))
/**
* MiraVersion checks the CDK version consistency across the Mira packge and the
* applications using Mira. It is capable of force-patching package.json files
* and running the NPM install.
*/
export class MiraVersion {
static instance: MiraVersion
cdkVersion: string
constructor () {
if (!MiraVersion.instance) {
MiraVersion.instance = this
}
const cdkVersion = this.getLocalMiraCDKVersion()
if (typeof cdkVersion === 'string') {
this.cdkVersion = cdkVersion
}
}
/**
* Checks a particular dependency CDK version.
*/
/* eslint-disable-next-line */
checkApplicationDependencyCDKVersion (pkg: any, pkgDeps: {[key: string]: string}, dep: string, autoFix = true): boolean {
if (!dep.startsWith('@aws-cdk') && !dep.startsWith('aws-cdk')) {
return false
}
const cdkVersion = pkgDeps[dep]
const miraVersion = this.cdkVersion
if (typeof miraVersion !== 'string') {
throw new Error('Mira contains CDK version issues.')
}
try {
this.checkDependency(cdkVersion, dep, miraVersion, 'Mira')
} catch (e) {
console.info(`${chalk.cyan('Info:')} Found a version mismatch between Mira and ${pkg.name}.` +
`\n\t${pkg.name} is ${cdkVersion}` +
`\n\tMira is ${miraVersion}`)
if (autoFix) {
pkgDeps[dep] = miraVersion
return true
}
}
return false
}
/**
* Gets the version of CDK used by an application. If there is a version
* mismatch, then modifies the package.json file of the application, informs
* the user and exits.
*/
checkApplicationCDKVersion (autoFix = true): void {
const pkgFile = FileHelpers.getPackageDirectory() + '/package.json'
const pkg = JSON.parse(fs.readFileSync(pkgFile, 'utf8'))
let madeChange = false
for (const dep in pkg.dependencies) {
const newChange = this.checkApplicationDependencyCDKVersion(pkg, pkg.dependencies, dep)
madeChange = madeChange || newChange
}
for (const dep in pkg.devDependencies) {
const newChange = this.checkApplicationDependencyCDKVersion(pkg, pkg.devDependencies, dep)
madeChange = madeChange || newChange
}
if (autoFix && madeChange) {
console.info(chalk.magenta('Patching'), 'package.json to match Mira CDK version: ', this.cdkVersion)
fs.writeFileSync(pkgFile, JSON.stringify(pkg, null, 2))
console.info(chalk.green('Success'), 'Patched package.json, please re-run `npm install`.')
process.exit()
}
}
/**
* Checks a dependency such that it has no wildcards in use. Optionally
* checks against an otherVersion.
*/
checkDependency (version: string, dep?: string, otherVersion?: string, otherDep?: string): boolean {
if (version.match(/[~^]/g) !== null) {
throw new Error(`${chalk.red('Version Error')}: The version of Mira use contains wildcard versions via 'aws-cdk'`)
}
if (otherVersion && version !== otherVersion) {
throw new Error(`${chalk.red('Version Error')}: Mira is using mismatched CDK dependency versions (${otherDep} is ${otherVersion} and ${dep} is ${version})`)
} else if (otherVersion && dep !== undefined) {
this.checkNodeModuleDependency(dep, otherVersion)
}
return true
}
/**
* Checks the local Mira dependencies when Mira has been installed as part
* of an app such that all Mira CDK deps should be installed as peer deps
* and also checks that any leftover CDK deps within Mira (not present in
* the app) are the same expected version as Mira specifies.
*/
/* eslint-disable-next-line */
checkLocalMiraCDKDependencies(version: string, pkg: any): void {
const pkgDir = `${FileHelpers.getPackageDirectory()}/node_modules/mira`
if (typeof pkgDir !== 'string') {
return
}
if (!fs.existsSync(`${pkgDir}/node_modules`)) {
// Nothing to check, no Mira `node_modules`.
return
}
if (args['ignore-version-errors'] !== undefined) {
return
}
const deps = Object.assign({}, pkg.dependencies, pkg.devDependencies)
for (const dep in deps) {
if (dep.startsWith('@aws-cdk') || dep.startsWith('aws-cdk')) {
if (fs.existsSync((`${pkgDir}/node_modules/${dep}`))) {
if (fs.existsSync(`${pkgDir}/../${dep}`)) {
throw new Error(`${chalk.red('Version Error')}: It seems like ${dep} was not ` +
'properly installed for Mira as a peerDependency. Try re-running ' +
'with the --ignore-version-errors flag after deleting ' +
'node_modules and reinstalling. If you' +
' encounter errors please log an issue ticket so the team' +
' can update the Mira package.json file. See ' +
'https://github.com/nearform/mira/issues/new')
}
const depPkg = JSON.parse(fs.readFileSync(`${pkgDir}/node_modules/${dep}/package.json`, 'utf8'))
if (depPkg.version !== version) {
throw new Error(`${chalk.red('Version Error')}: the ` +
`Mira dependency ${dep} has a version of ${depPkg.version} but` +
` this mismatches the expected Mira CDK version of ${version}.` +
' Try re-running with the --ignore-version-errors flag and' +
' deleting node_modules, then reinstalling. If' +
' you encounter errors please log an issue ticket so the team.' +
' See https://github.com/nearform/mira/issues/new')
}
}
}
}
}
/**
* Checks that the file within node_modules matches what is expected for
* the dependency provided and the version. If any of these checks fails,
* an error is thrown.
*/
checkNodeModuleDependency (dep: string, version: string): void {
const pkgDir = FileHelpers.getPackageDirectory()
if (!fs.existsSync(`${pkgDir}/node_modules/${dep}/package.json`)) {
throw new Error(`${chalk.red('Version Error')}: Package ${dep} not found in node_modules` +
', did you forget to install?')
}
const depPkg = JSON.parse(fs
.readFileSync(`${pkgDir}/node_modules/${dep}/package.json`, 'utf8'))
if (depPkg.version !== version) {
throw new Error(`${chalk.red('Version Error')}: The ` +
`version for ${dep} of ${depPkg.version} did not match the expected` +
` value of ${version}. Try deleting node_modules and reinstalling.`)
}
}
/**
* Gets the CDK version within this local version of Mira. If there are
* any version range operators used, throws an error.
*/
getLocalMiraCDKVersion (): string|boolean {
try {
if (!fs.existsSync(`${__dirname}/../../package.json`)) {
return false
}
const pkg = JSON.parse(fs.readFileSync(`${__dirname}/../../package.json`, 'utf8'))
const deps = Object.assign({}, pkg.dependencies, pkg.devDependencies)
const cdkVersion = deps['aws-cdk']
this.checkDependency(cdkVersion)
for (const dep in deps) {
if (dep.startsWith('@aws-cdk')) {
const cdkDepVersion = deps[dep]
this.checkDependency(cdkVersion, dep, cdkDepVersion, 'aws-cdk')
}
}
this.checkLocalMiraCDKDependencies(cdkVersion, pkg)
return cdkVersion
} catch (e) {
console.warn('An error occurred while reading the CDK version ' +
'used by Mira:', chalk.grey(e))
return false
}
}
}
export default new MiraVersion()