Add rondo update script
This commit is contained in:
parent
a8af27bac3
commit
fc613f426b
@ -14,4 +14,4 @@
|
||||
"types": "lib/index.d.ts",
|
||||
"devDependencies": {},
|
||||
"module": "lib/index.js"
|
||||
}
|
||||
}
|
||||
@ -1,9 +1,9 @@
|
||||
import {format} from 'util'
|
||||
|
||||
export function error(message: string, ...values: any[]) {
|
||||
process.stderr.write(format(message + '\n', ...values))
|
||||
process.stderr.write(format(message, ...values) + '\n')
|
||||
}
|
||||
|
||||
export function info(message: string, ...values: any[]) {
|
||||
process.stdout.write(format(message + '\n', ...values))
|
||||
process.stdout.write(format(message, ...values) + '\n')
|
||||
}
|
||||
|
||||
@ -3,3 +3,4 @@ export * from './build'
|
||||
export * from './exportDir'
|
||||
export * from './intergen'
|
||||
export * from './syncEsm'
|
||||
export * from './update'
|
||||
|
||||
80
packages/scripts/src/scripts/update.test.ts
Normal file
80
packages/scripts/src/scripts/update.test.ts
Normal file
@ -0,0 +1,80 @@
|
||||
jest.mock('child_process')
|
||||
jest.mock('fs')
|
||||
jest.mock('../log')
|
||||
|
||||
import cp from 'child_process'
|
||||
import * as fs from 'fs'
|
||||
import {update, IOutdated} from './update'
|
||||
|
||||
describe('update', () => {
|
||||
|
||||
const stringify = (obj: object) => JSON.stringify(obj, null, ' ')
|
||||
|
||||
const readMock = fs.readFileSync as jest.Mock<typeof fs.readFileSync>
|
||||
const writeMock = fs.writeFileSync as jest.Mock<typeof fs.writeFileSync>
|
||||
const cpMock = cp.execFileSync as jest.Mock<typeof cp.execFileSync>
|
||||
|
||||
let outdated: Record<string, IOutdated> = {}
|
||||
beforeEach(() => {
|
||||
outdated = {}
|
||||
|
||||
cpMock.mockClear()
|
||||
readMock.mockClear()
|
||||
writeMock.mockClear()
|
||||
|
||||
cpMock.mockImplementation(() => {
|
||||
const err = new Error('Exit code 1');
|
||||
(err as any).stdout = stringify(outdated)
|
||||
throw err
|
||||
})
|
||||
readMock.mockReturnValue(stringify({
|
||||
name: 'test',
|
||||
dependencies: {
|
||||
a: '^1.2.3',
|
||||
},
|
||||
devDependencies: {
|
||||
b: '^3.4.6',
|
||||
},
|
||||
}))
|
||||
})
|
||||
|
||||
it('does not change when no changes', async () => {
|
||||
cpMock.mockReturnValue('{}')
|
||||
await update('update', '/my/dir')
|
||||
expect(writeMock.mock.calls.length).toBe(0)
|
||||
})
|
||||
|
||||
it('does not change when npm outdated output is empty', async () => {
|
||||
cpMock.mockReturnValue('')
|
||||
await update('update', '/my/dir')
|
||||
expect(writeMock.mock.calls.length).toBe(0)
|
||||
})
|
||||
|
||||
it('updates outdated dependencies in package.json', async () => {
|
||||
outdated = {
|
||||
a: {
|
||||
wanted: '1.2.3',
|
||||
latest: '1.4.0',
|
||||
location: '',
|
||||
},
|
||||
b: {
|
||||
wanted: '3.4.6',
|
||||
latest: '3.4.7',
|
||||
location: '',
|
||||
},
|
||||
}
|
||||
await update('update', '/my/dir')
|
||||
expect(writeMock.mock.calls).toEqual([[
|
||||
'/my/dir/package.json', stringify({
|
||||
name: 'test',
|
||||
dependencies: {
|
||||
a: '^1.4.0',
|
||||
},
|
||||
devDependencies: {
|
||||
b: '^3.4.7',
|
||||
},
|
||||
}),
|
||||
]])
|
||||
})
|
||||
|
||||
})
|
||||
87
packages/scripts/src/scripts/update.ts
Normal file
87
packages/scripts/src/scripts/update.ts
Normal file
@ -0,0 +1,87 @@
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
import cp from 'child_process'
|
||||
import {argparse, arg} from '@rondo.dev/argparse'
|
||||
import {info} from '../log'
|
||||
|
||||
export interface IOutdated {
|
||||
wanted: string
|
||||
latest: string
|
||||
location: string
|
||||
}
|
||||
|
||||
export interface IPackage {
|
||||
dependencies?: Record<string, string>
|
||||
devDependencies?: Record<string, string>
|
||||
}
|
||||
|
||||
function findOutdated(cwd: string): Record<string, IOutdated> {
|
||||
try {
|
||||
const result = cp.execFileSync('npm', ['outdated', '--json'], {
|
||||
cwd,
|
||||
encoding: 'utf8',
|
||||
})
|
||||
return result === '' ? {} : JSON.parse(result)
|
||||
} catch (err) {
|
||||
// npm outdated will exit with code 1 if there are outdated dependencies
|
||||
return JSON.parse(err.stdout)
|
||||
}
|
||||
}
|
||||
|
||||
export async function update(...argv: string[]) {
|
||||
const {parse} = argparse({
|
||||
dirs: arg('string[]', {positional: true, default: ['.'], n: '+'}),
|
||||
prefix: arg('string', {default: '^'}),
|
||||
})
|
||||
const {dirs, prefix} = parse(argv)
|
||||
|
||||
let updates = 0
|
||||
for (const dir of dirs) {
|
||||
info(dir)
|
||||
const outdatedByName = findOutdated(dir)
|
||||
|
||||
const pkgFile = path.join(dir, 'package.json')
|
||||
const pkg: IPackage = JSON.parse(fs.readFileSync(pkgFile, 'utf8'))
|
||||
let pkgUpdate: IPackage = pkg
|
||||
|
||||
// tslint:disable-next-line
|
||||
for (const name in outdatedByName) {
|
||||
const outdated = outdatedByName[name]
|
||||
pkgUpdate = updateDependency(
|
||||
pkgUpdate, 'dependencies', name, prefix, outdated)
|
||||
pkgUpdate = updateDependency(
|
||||
pkgUpdate, 'devDependencies', name, prefix, outdated)
|
||||
}
|
||||
|
||||
if (pkgUpdate !== pkg) {
|
||||
updates += 1
|
||||
info('Writing updates...')
|
||||
fs.writeFileSync(pkgFile, JSON.stringify(pkgUpdate, null, ' '))
|
||||
}
|
||||
}
|
||||
|
||||
if (updates) {
|
||||
info('Done! Do not forget to run npm install!')
|
||||
}
|
||||
}
|
||||
|
||||
function updateDependency(
|
||||
pkg: IPackage,
|
||||
key: 'dependencies' | 'devDependencies',
|
||||
name: string,
|
||||
prefix: string,
|
||||
version: IOutdated,
|
||||
): IPackage {
|
||||
const deps = pkg[key]
|
||||
if (!deps || !deps[name] || version.wanted === version.latest) {
|
||||
return pkg
|
||||
}
|
||||
info(' %s.%s %s ==> %s', key, name, version.wanted, version.latest)
|
||||
return {
|
||||
...pkg,
|
||||
[key]: {
|
||||
...deps,
|
||||
[name]: prefix + version.latest,
|
||||
},
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user