Skip to content
This repository has been archived by the owner on Apr 21, 2022. It is now read-only.

Commit

Permalink
feat: added publish:github
Browse files Browse the repository at this point in the history
  • Loading branch information
jdx committed Apr 7, 2018
1 parent 40e844e commit 37d56f3
Show file tree
Hide file tree
Showing 8 changed files with 197 additions and 47 deletions.
2 changes: 2 additions & 0 deletions package.json
Expand Up @@ -14,8 +14,10 @@
"@oclif/errors": "^1.0.3",
"@oclif/plugin-help": "^1.2.3",
"@oclif/plugin-warn-if-update-available": "^1.2.4",
"@octokit/rest": "^15.2.6",
"aws-sdk": "^2.222.1",
"cli-ux": "^3.3.27",
"debug": "^3.1.0",
"fs-extra": "^5.0.0",
"lodash": "^4.17.5",
"lodash.template": "^4.4.0",
Expand Down
2 changes: 1 addition & 1 deletion src/commands/pack.ts
Expand Up @@ -39,7 +39,7 @@ outputs tarball of CLI including a windows-x64 binary to ./dist/mycli-v0.0.0-win
if (platform && !arch) throw new Error('--platform and --arch must be specified together')

const config = await Tarballs.config(root)
const version = await Tarballs.version(config)
const version = channel === 'stable' ? config.version : `${config.version}-${channel}.${await Tarballs.gitSha(config.root)}`
const base = await Tarballs.base(config, platform, arch, version)
const tmp = await Tarballs.tmp(config)
const workspace = path.join(tmp, base)
Expand Down
78 changes: 78 additions & 0 deletions src/commands/publish/github.ts
@@ -0,0 +1,78 @@
import {Command, flags} from '@oclif/command'
import * as Octokit from '@octokit/rest'
import * as fs from 'fs-extra'
import * as path from 'path'
import * as qq from 'qqjs'

import * as Tarballs from '../../tarballs'
import {log as action} from '../../tarballs/log'

export default class Publish extends Command {
static description = 'publish an oclif CLI to GitHub Releases'

static flags = {
root: flags.string({char: 'r', description: 'path to oclif CLI root', default: '.', required: true}),
targets: flags.string({char: 't', description: 'comma-separated targets to build for (e.g. darwin-x64, win32-x86)', required: true}),
'node-version': flags.string({description: 'node version of binary to get', default: process.versions.node, required: true}),
xz: flags.boolean({description: 'also create xz tarballs'}),
prerelease: flags.boolean({description: 'identify as prerelease'}),
draft: flags.boolean({description: 'create an unpublished release'}),
}

async run() {
if (!process.env.GH_TOKEN) throw new Error('GH_TOKEN must be set')
const {flags} = this.parse(Publish)
if (process.platform === 'win32') throw new Error('pack does not function on windows')
const {'node-version': nodeVersion} = flags
const channel = flags.prerelease ? 'prerelease' : 'stable'
const root = path.resolve(flags.root)
const config = await Tarballs.config(root)
const version = config.version
const baseWorkspace = qq.join([config.root, 'tmp', 'base'])

// first create the generic base workspace that will be copied later
await Tarballs.build({config, channel, output: baseWorkspace, version})

const tarballs: {target: string, tarball: string}[] = []
for (let [platform, arch] of flags.targets.split(',').map(t => t.split('-'))) {
const t = await Tarballs.target({config, platform, arch, channel, version, baseWorkspace, nodeVersion, xz: flags.xz})
tarballs.push(t)
}

const octokit = new Octokit()
octokit.authenticate({
type: 'token',
token: process.env.GH_TOKEN,
})
const tag = `v${version}`
action(`creating ${tag} release`)
const [owner, repo] = config.pjson.repository.split('/')
const {data: release} = await octokit.repos.createRelease({
owner,
repo,
target_commitish: await Tarballs.gitSha(config.root),
tag_name: tag,
prerelease: flags.prerelease,
draft: flags.draft,
})

for (let {tarball} of tarballs) {
const upload = async (file: string) => {
action(`uploading ${tarball}`)
await octokit.repos.uploadAsset({
url: release.upload_url,
file: fs.createReadStream(file),
contentType: 'application/gzip',
contentLength: fs.statSync(file).size,
name: qq.path.basename(file),
label: qq.path.basename(file),
})
}
await upload(`${tarball}.tar.gz`)
if (flags.xz) await upload(`${tarball}.tar.xz`)
}
if (config.pjson.scripts.postpublish) {
await qq.x('npm', ['run', 'postpublish'])
}
}
}
51 changes: 13 additions & 38 deletions src/commands/publish/s3.ts
Expand Up @@ -2,9 +2,9 @@ import {Command, flags} from '@oclif/command'
import * as path from 'path'
import * as qq from 'qqjs'

import * as S3 from '../s3'
import * as Tarballs from '../tarballs'
import {log as action} from '../tarballs/log'
import * as S3 from '../../s3'
import * as Tarballs from '../../tarballs'
import {log as action} from '../../tarballs/log'

export type Manifest = {
version: string
Expand All @@ -14,10 +14,7 @@ export type Manifest = {
}

export default class Publish extends Command {
static description = `publish an oclif CLI
Can publish either to S3 or as GitHub releases.
`
static description = 'publish an oclif CLI to S3'

static flags = {
root: flags.string({char: 'r', description: 'path to oclif CLI root', default: '.', required: true}),
Expand All @@ -34,50 +31,28 @@ Can publish either to S3 or as GitHub releases.
const {channel, 'node-version': nodeVersion} = flags
const root = path.resolve(flags.root)
const config = await Tarballs.config(root)
const version = await Tarballs.version(config)
const version = channel === 'stable' ? config.version : `${config.version}-${channel}.${await Tarballs.gitSha(config.root)}`
const baseWorkspace = qq.join([config.root, 'tmp', 'base'])

// first create the generic base workspace that will be copied later
await Tarballs.build({config, channel, output: baseWorkspace, version})

const tarballs: [string, string][] = []
const tarballs: {target: string, tarball: string}[] = []
for (let [platform, arch] of flags.targets.split(',').map(t => t.split('-'))) {
const base = await Tarballs.base(config, platform, arch, version)
action(`building ${base}`)
const targetWorkspace = qq.join([config.root, 'tmp', base])
await qq.rm(targetWorkspace)
await qq.cp(baseWorkspace, targetWorkspace)
await Tarballs.writeBinScripts({config, output: targetWorkspace, platform})
await Tarballs.fetchNodeBinary({
nodeVersion,
output: path.join(targetWorkspace, 'bin', 'node'),
platform,
arch,
tmp: qq.join([config.root, 'tmp']),
})
const tarball = path.join(config.root, 'dist', base)
const target = path.join(config.root, 'dist', [platform, arch].join('-'))
tarballs.push([tarball, target])
await Tarballs.pack({from: targetWorkspace, to: tarball, as: config.bin, xz: flags.xz})
const manifest: Manifest = {
channel,
version,
sha256gz: await qq.hash('sha256', `${tarball}.tar.gz`),
}
if (flags.xz) manifest.sha256xz = await qq.hash('sha256', `${tarball}.tar.xz`)
await qq.writeJSON(target, manifest)
const t = await Tarballs.target({config, platform, arch, channel, version, baseWorkspace, nodeVersion, xz: flags.xz})
tarballs.push(t)
}
const prefix = `${config.bin}/channels/${channel}`
const Bucket = flags.bucket || process.env.AWS_S3_BUCKET
if (!Bucket) throw new Error('must pass --bucket or set AWS_S3_BUCKET')
const upload = async (local: string, remote: string) => {
await S3.uploadFile(local, {Bucket, Key: remote, ACL: 'public-read'})
}
for (let [t, target] of tarballs) {
action(`uploading ${t}`)
const base = path.basename(t)
await upload(`${t}.tar.gz`, `${prefix}/${base}/${base}.tar.gz`)
if (flags.xz) await upload(`${t}.tar.xz`, `${prefix}/${base}/${base}.tar.xz`)
for (let {tarball, target} of tarballs) {
action(`uploading ${tarball}`)
const base = path.basename(tarball)
await upload(`${tarball}.tar.gz`, `${prefix}/${base}/${base}.tar.gz`)
if (flags.xz) await upload(`${tarball}.tar.xz`, `${prefix}/${base}/${base}.tar.xz`)
await upload(target, `${prefix}/${path.basename(target)}`)
}
action('uploading manifest')
Expand Down
4 changes: 2 additions & 2 deletions src/tarballs/bin.ts
Expand Up @@ -57,6 +57,6 @@ fi
await qq.chmod(bin, 0o755)
}

if (!platform || platform === 'win32') writeWin32()
if (!platform || platform !== 'win32') writeUnix()
if (!platform || platform === 'win32') await writeWin32()
if (!platform || platform !== 'win32') await writeUnix()
}
39 changes: 39 additions & 0 deletions src/tarballs/build.ts
@@ -1,7 +1,19 @@
import {IConfig} from '@oclif/config'
import * as path from 'path'
import * as qq from 'qqjs'

import {writeBinScripts} from './bin'
import {base as getBase} from './config'
import {log} from './log'
import {fetchNodeBinary} from './node'
import {pack} from './pack'

export type Manifest = {
version: string
channel: string
sha256gz: string
sha256xz?: string
}

export async function build({channel, config, output, version}: {output: string, channel: string, config: IConfig, version: string}) {
const prevCwd = qq.cwd()
Expand Down Expand Up @@ -55,3 +67,30 @@ export async function build({channel, config, output, version}: {output: string,
await prune()
qq.cd(prevCwd)
}

export async function target({config, platform, arch, channel, version, baseWorkspace, nodeVersion, xz}: {config: IConfig, platform: string, arch: string, channel: string, version: string, baseWorkspace: string, nodeVersion: string, xz: boolean}) {
const base = await getBase(config, platform, arch, version)
log(`building ${base}`)
const targetWorkspace = qq.join([config.root, 'tmp', base])
await qq.rm(targetWorkspace)
await qq.cp(baseWorkspace, targetWorkspace)
await writeBinScripts({config, output: targetWorkspace, platform})
await fetchNodeBinary({
nodeVersion,
output: path.join(targetWorkspace, 'bin', 'node'),
platform,
arch,
tmp: qq.join([config.root, 'tmp']),
})
const tarball = path.join(config.root, 'dist', base)
const target = path.join(config.root, 'dist', [platform, arch].join('-'))
await pack({from: targetWorkspace, to: tarball, as: config.bin, xz})
const manifest: Manifest = {
channel,
version,
sha256gz: await qq.hash('sha256', `${tarball}.tar.gz`),
}
if (xz) manifest.sha256xz = await qq.hash('sha256', `${tarball}.tar.xz`)
await qq.writeJSON(target, manifest)
return {tarball, target}
}
7 changes: 2 additions & 5 deletions src/tarballs/config.ts
Expand Up @@ -2,11 +2,8 @@ import * as Config from '@oclif/config'
import * as path from 'path'
import * as qq from 'qqjs'

export async function version(config: Config.IConfig) {
if (!await qq.exists('.git')) return config.version
// add git sha to version if in a git repo
const sha = (await qq.x.stdout('git', ['rev-parse', '--short', 'HEAD'], {cwd: config.root}))
return `${config.version}-${sha}`
export function gitSha(cwd: string) {
return qq.x.stdout('git', ['rev-parse', '--short', 'HEAD'], {cwd})
}

export async function base(config: Config.IConfig, platform: string | undefined, arch: string | undefined, version: string) {
Expand Down
61 changes: 60 additions & 1 deletion yarn.lock
Expand Up @@ -139,6 +139,19 @@
dependencies:
tslint-xo "^0.7.0"

"@octokit/rest@^15.2.6":
version "15.2.6"
resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-15.2.6.tgz#16226f58fbf0ba88f631848fb622dfe0ad410c0c"
dependencies:
before-after-hook "^1.1.0"
btoa-lite "^1.0.0"
debug "^3.1.0"
http-proxy-agent "^2.1.0"
https-proxy-agent "^2.2.0"
lodash "^4.17.4"
node-fetch "^2.1.1"
url-template "^2.0.8"

"@types/chai@^4.1.2":
version "4.1.2"
resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.1.2.tgz#f1af664769cfb50af805431c407425ed619daa21"
Expand Down Expand Up @@ -203,6 +216,12 @@
version "2.2.1"
resolved "https://registry.yarnpkg.com/@types/write-json-file/-/write-json-file-2.2.1.tgz#74155aaccbb0d532be21f9d66bebc4ea875a5a62"

agent-base@4, agent-base@^4.1.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.0.tgz#9838b5c3392b962bad031e6a4c5e1024abec45ce"
dependencies:
es6-promisify "^5.0.0"

ansi-escapes@^3.0.0, ansi-escapes@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30"
Expand Down Expand Up @@ -320,6 +339,10 @@ base@^0.11.1:
mixin-deep "^1.2.0"
pascalcase "^0.1.1"

before-after-hook@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-1.1.0.tgz#83165e15a59460d13702cb8febd6a1807896db5a"

brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
Expand Down Expand Up @@ -348,6 +371,10 @@ browser-stdout@1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60"

btoa-lite@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/btoa-lite/-/btoa-lite-1.0.0.tgz#337766da15801210fdd956c22e9c6891ab9d0337"

buffer@4.9.1:
version "4.9.1"
resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298"
Expand Down Expand Up @@ -578,6 +605,16 @@ error-ex@^1.3.1:
dependencies:
is-arrayish "^0.2.1"

es6-promise@^4.0.3:
version "4.2.4"
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.4.tgz#dc4221c2b16518760bd8c39a52d8f356fc00ed29"

es6-promisify@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203"
dependencies:
es6-promise "^4.0.3"

escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
Expand Down Expand Up @@ -835,6 +872,20 @@ http-call@^5.1.0:
tslib "^1.9.0"
tunnel-agent "^0.6.0"

http-proxy-agent@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405"
dependencies:
agent-base "4"
debug "3.1.0"

https-proxy-agent@^2.2.0:
version "2.2.1"
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0"
dependencies:
agent-base "^4.1.0"
debug "^3.1.0"

ieee754@1.1.8:
version "1.1.8"
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4"
Expand Down Expand Up @@ -1092,7 +1143,7 @@ lodash.templatesettings@^4.0.0:
dependencies:
lodash._reinterpolate "~3.0.0"

lodash@^4.0.0, lodash@^4.17.5:
lodash@^4.0.0, lodash@^4.17.4, lodash@^4.17.5:
version "4.17.5"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511"

Expand Down Expand Up @@ -1219,6 +1270,10 @@ nice-try@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4"

node-fetch@^2.1.1:
version "2.1.2"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.1.2.tgz#ab884e8e7e57e38a944753cec706f788d1768bb5"

normalize-package-data@^2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f"
Expand Down Expand Up @@ -1773,6 +1828,10 @@ urix@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"

url-template@^2.0.8:
version "2.0.8"
resolved "https://registry.yarnpkg.com/url-template/-/url-template-2.0.8.tgz#fc565a3cccbff7730c775f5641f9555791439f21"

url@0.10.3:
version "0.10.3"
resolved "https://registry.yarnpkg.com/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64"
Expand Down

0 comments on commit 37d56f3

Please sign in to comment.