Add rondo update script
This commit is contained in:
parent
a8af27bac3
commit
fc613f426b
@ -14,4 +14,4 @@
|
|||||||
"types": "lib/index.d.ts",
|
"types": "lib/index.d.ts",
|
||||||
"devDependencies": {},
|
"devDependencies": {},
|
||||||
"module": "lib/index.js"
|
"module": "lib/index.js"
|
||||||
}
|
}
|
||||||
@ -1,9 +1,9 @@
|
|||||||
import {format} from 'util'
|
import {format} from 'util'
|
||||||
|
|
||||||
export function error(message: string, ...values: any[]) {
|
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[]) {
|
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 './exportDir'
|
||||||
export * from './intergen'
|
export * from './intergen'
|
||||||
export * from './syncEsm'
|
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