Skip to content

Commit

Permalink
feat(scripts): support bump command
Browse files Browse the repository at this point in the history
  • Loading branch information
shigma committed Feb 20, 2022
1 parent a8e19a3 commit 673e6db
Show file tree
Hide file tree
Showing 8 changed files with 244 additions and 34 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"scripts": {
"build": "yarn compile && yarn dtsc && yarn fe",
"dtsc": "node -r ./build/register build/dtsc",
"bump": "node -r ./build/register build/bump",
"bump": "koishi-scripts bump",
"compile": "node -r ./build/register build/compile",
"dep": "node -r ./build/register build/dep",
"docs": "yarn workspace docs",
Expand All @@ -33,7 +33,7 @@
"test:html": "rimraf coverage && c8 -r html yarn test",
"test:text": "c8 -r text yarn test",
"lint": "eslint packages plugins --ext=ts --cache",
"pub": "node -r ./build/register build/publish",
"pub": "koishi-scripts publish",
"scaffold": "yarn compile koishi && yarn create-koishi test",
"start": "yarn compile && cross-env TS_NODE_PROJECT=../tsconfig.test.json yarn workspace test koishi start --watch .. -r ../build/register",
"shiki": "yarn workspace bot-shiki"
Expand Down
2 changes: 2 additions & 0 deletions packages/scripts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,12 @@
},
"dependencies": {
"@koishijs/cli": "^4.2.2",
"@koishijs/client": "^3.1.1",
"cac": "^6.7.12",
"cross-spawn": "^7.0.3",
"fs-extra": "^10.0.0",
"globby": "^11.0.4",
"kleur": "^4.1.4",
"latest-version": "^5.1.0",
"ora": "^5.4.1",
"prompts": "^2.4.2",
Expand Down
2 changes: 2 additions & 0 deletions packages/scripts/src/bin.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env node

import registerBuildCommand from './build'
import registerBumpCommand from './bump'
import registerInitCommand from './init'
import registerPublishCommand from './publish'
import CAC from 'cac'
Expand All @@ -10,6 +11,7 @@ const { version } = require('../package.json')
const cli = CAC('koishi-scripts').help().version(version)

registerBuildCommand(cli)
registerBumpCommand(cli)
registerInitCommand(cli)
registerPublishCommand(cli)

Expand Down
14 changes: 9 additions & 5 deletions packages/scripts/src/build.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { CAC } from 'cac'
import { writeFile } from 'fs-extra'
import { buildExtension } from '@koishijs/client/lib'
import { cwd, getPackages, PackageJson, spawnAsync, TsConfig } from './utils'

interface Node {
Expand All @@ -9,12 +10,11 @@ interface Node {
next?: Set<string>
}

function initGraph(names: string[]) {
const packages = getPackages(names)
function initGraph(packages: Record<string, PackageJson>) {
const nodes: Record<string, Node> = {}
for (const path in packages) {
const meta = packages[path]
if (!meta || meta.private) return
if (!meta.main) return
nodes[meta.name] = { path, meta, prev: [], next: new Set() }
}

Expand All @@ -41,7 +41,7 @@ async function buildGraph(nodes: Record<string, Node>) {
const node = nodes[name]
if (node.next.size) return true
delete nodes[name]
config.references.unshift({ path: './' + node.path })
config.references.unshift({ path: '.' + node.path })
node.prev.forEach(dep => {
nodes[dep].next.delete(name)
})
Expand All @@ -68,7 +68,11 @@ async function buildGraph(nodes: Record<string, Node>) {
export default function (cli: CAC) {
cli.command('build [...name]', 'build packages')
.action(async (names: string[], options) => {
const nodes = initGraph(names)
const packages = await getPackages(names)
const nodes = initGraph(packages)
await buildGraph(nodes)
for (const path in packages) {
await buildExtension(cwd + path)
}
})
}
147 changes: 147 additions & 0 deletions packages/scripts/src/bump.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import { CAC } from 'cac'
import { writeFile } from 'fs-extra'
import { gt, SemVer } from 'semver'
import { cyan, green } from 'kleur'
import { cwd, exit, getPackages, PackageJson } from './utils'

const bumpTypes = ['major', 'minor', 'patch', 'prerelease', 'version'] as const
type BumpType = typeof bumpTypes[number]

class Package {
meta: PackageJson
version: SemVer
dirty: boolean

constructor(public path: string) {
this.meta = require(`${cwd}/${path}/package.json`)
this.version = new SemVer(this.meta.version)
}

bump(flag: BumpType, options: any) {
if (this.meta.private) return
let verion = new SemVer(this.meta.version)
if (!flag) {
if (verion.prerelease.length) {
const prerelease = verion.prerelease.slice() as [string, number]
prerelease[1] += 1
verion.prerelease = prerelease
} else {
verion.patch += 1
}
} else if (flag === 'version') {
verion = new SemVer(options.version)
} else if (flag === 'prerelease') {
if (verion.prerelease.length) {
verion.prerelease = [{
alpha: 'beta',
beta: 'rc',
}[verion.prerelease[0]], 0]
} else {
verion = new SemVer(`${verion.major + 1}.0.0-alpha.0`)
}
} else {
if (verion.prerelease.length) {
verion.prerelease = []
} else {
verion[flag] += 1
if (flag !== 'patch') verion.patch = 0
if (flag === 'major') verion.minor = 0
}
}
if (gt(verion, this.version)) {
this.dirty = true
this.version = verion
return verion.format()
}
}

save() {
this.meta.version = this.version.format()
return writeFile(`${cwd}/${this.path}/package.json`, JSON.stringify(this.meta, null, 2))
}
}

class Graph {
nodes: Record<string, Package> = {}

constructor(public options: any) {}

async init() {
const workspaces = await getPackages([])
for (const path in workspaces) {
this.nodes[path] = new Package(path)
}
return workspaces
}

each<T>(callback: (node: Package, path: string) => T) {
const results: T[] = []
for (const path in this.nodes) {
results.push(callback(this.nodes[path], path))
}
return results
}

bump(node: Package, flag: BumpType) {
const version = node.bump(flag, this.options)
if (!version) return
const dependents = new Set<Package>()
this.each((target) => {
const { devDependencies, peerDependencies, dependencies, optionalDependencies } = target.meta
const { name } = node.meta
if (target.meta.name === name) return
Object.entries({ devDependencies, peerDependencies, dependencies, optionalDependencies })
.filter(([, dependencies = {}]) => dependencies[name])
.forEach(([type]) => {
target.meta[type][name] = '^' + version
target.dirty = true
if (type !== 'devDependencies') {
dependents.add(target)
}
})
})
if (!this.options.recursive) return
dependents.forEach(dep => this.bump(dep, flag))
}

async save() {
await Promise.all(this.each((node) => {
if (!node.dirty) return
if (node.version.format() === node.meta.version) {
console.log(`- ${node.meta.name}: updated`)
} else {
console.log(`- ${node.meta.name}: ${cyan(node.meta.version)} => ${green(node.meta.version)}`)
}
return node.save()
}))
}
}

export default function (cli: CAC) {
cli.command('bump [...names]', 'bump versions')
.option('-1, --major', '')
.option('-2, --minor', '')
.option('-3, --patch', '')
.option('-p, --prerelease', '')
.option('-v, --version <ver>', '')
.option('-r, --recursive', '')
.action(async (names: string[], options) => {
if (!names) exit('no package specified')

const graph = new Graph(options)
const workspaces = await graph.init()
const packages = await getPackages(names, { workspaces })

const flag = (() => {
for (const type of bumpTypes) {
if (type in options) return type
}
})()

for (const path in packages) {
graph.bump(graph.nodes[path], flag)
}

await graph.save()
})
}
28 changes: 13 additions & 15 deletions packages/scripts/src/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,15 @@ import { CAC } from 'cac'
import { promises as fsp } from 'fs'
import { resolve } from 'path'
import { getAgent } from '@koishijs/cli'
import { cwd, meta } from './utils'
import spawn from 'cross-spawn'
import prompts from 'prompts'

class Runner {
class Initiator {
root: string
name: string
fullname: string

constructor(public meta: any) {}

async init(name: string) {
this.name = name || await this.getName()
this.fullname = name.includes('/')
? name.replace('/', '/koishi-plugin-')
: 'koishi-plugin-' + name
this.root = resolve(process.cwd(), 'plugins', name)
await this.write()
}

async start(name: string) {
const [agent] = await Promise.all([
getAgent(),
Expand All @@ -30,6 +20,15 @@ class Runner {
spawn.sync(agent, args, { stdio: 'inherit' })
}

async init(name: string) {
this.name = name || await this.getName()
this.fullname = name.includes('/')
? name.replace('/', '/koishi-plugin-')
: 'koishi-plugin-' + name
this.root = resolve(cwd, 'plugins', name)
await this.write()
}

async getName() {
const { name } = await prompts({
type: 'text',
Expand Down Expand Up @@ -66,7 +65,7 @@ class Runner {
'plugin',
],
peerDependencies: {
koishi: this.meta.dependencies.koishi,
koishi: meta.dependencies.koishi,
},
}, null, 2))
}
Expand Down Expand Up @@ -100,7 +99,6 @@ export default function (cli: CAC) {
cli.command('init [name]', 'init a new plugin')
.alias('create')
.action(async (name: string, options) => {
const meta = require(process.cwd() + '/package.json')
new Runner(meta).start(name)
new Initiator().start(name)
})
}
11 changes: 6 additions & 5 deletions packages/scripts/src/publish.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@ function publish(folder: string, name: string, version: string, tag: string) {

export default function (cli: CAC) {
cli.command('publish [...name]', 'publish packages')
.alias('pub')
.action(async (names: string[], options) => {
const entries = Object.entries(await getPackages(names))
const entries = Object.entries(await getPackages(names, { ignorePrivate: true }))
const spinner = ora()
const bumpMap: Record<string, PackageJson> = {}

Expand All @@ -49,12 +50,12 @@ export default function (cli: CAC) {
}))
spinner.succeed()

for (const folder in bumpMap) {
const { name, version } = bumpMap[folder]
for (const path in bumpMap) {
const { name, version } = bumpMap[path]
if (name === 'koishi') {
await copyFile(`${cwd}/README.md`, `${cwd}/${folder}/README.md`)
await copyFile(`${cwd}/README.md`, `${cwd}${path}/README.md`)
}
await publish(folder, name, version, isNext(version) ? 'next' : 'latest')
await publish(path, name, version, isNext(version) ? 'next' : 'latest')
}

spinner.succeed('All workspaces are up to date.')
Expand Down
Loading

0 comments on commit 673e6db

Please sign in to comment.