github-desktop/script/draft-release/run.ts

101 lines
3.4 KiB
TypeScript
Raw Normal View History

2018-02-04 11:18:09 +00:00
import { sort as semverSort, SemVer } from 'semver'
import { spawn } from '../changelog/spawn'
import { getLogLines } from '../changelog/git'
2018-02-04 04:16:32 +00:00
import {
convertToChangelogFormat,
getChangelogEntriesSince,
} from '../changelog/parser'
2018-02-04 11:18:09 +00:00
import { Channel } from './channel'
import { getNextVersionNumber } from './version'
const jsonStringify: (obj: any) => string = require('json-pretty')
2018-02-09 04:04:30 +00:00
async function getLatestRelease(options: {
excludeBetaReleases: boolean
}): Promise<string> {
const allTags = await spawn('git', ['tag'])
let releaseTags = allTags
.split('\n')
.filter(tag => tag.startsWith('release-'))
2020-01-30 14:34:14 +00:00
.filter(tag => !tag.includes('-linux'))
.filter(tag => !tag.includes('-test'))
2018-02-09 04:04:30 +00:00
if (options.excludeBetaReleases) {
2020-01-30 14:34:14 +00:00
releaseTags = releaseTags.filter(tag => !tag.includes('-beta'))
}
const releaseVersions = releaseTags.map(tag => tag.substr(8))
const sortedTags = semverSort(releaseVersions)
const latestTag = sortedTags[sortedTags.length - 1]
2018-02-09 03:55:45 +00:00
return latestTag instanceof SemVer ? latestTag.raw : latestTag
}
2018-02-04 11:17:04 +00:00
function parseChannel(arg: string): Channel {
2018-02-09 04:04:30 +00:00
if (arg === 'production' || arg === 'beta' || arg === 'test') {
2018-02-04 01:15:29 +00:00
return arg
}
throw new Error(`An invalid channel ${arg} has been provided`)
}
2018-02-04 04:16:32 +00:00
function printInstructions(nextVersion: string, entries: Array<string>) {
2018-02-09 03:55:45 +00:00
const object: any = {}
object[`${nextVersion}`] = entries.sort()
2018-02-09 04:47:47 +00:00
const steps = [
`Update the app/package.json 'version' to '${nextVersion}' (make sure this aligns with semver format of 'major.minor.patch')`,
`Concatenate this to the beginning of the 'releases' element in the changelog.json as a starting point:\n${jsonStringify(
2018-02-09 04:47:47 +00:00
object
)}\n`,
2020-01-29 14:32:43 +00:00
'Revise the release notes according to https://github.com/desktop/desktop/blob/development/docs/process/writing-release-notes.md',
'Commit the changes (on development or as new branch) and push them to GitHub',
'Read this to perform the release: https://github.com/desktop/desktop/blob/development/docs/process/releasing-updates.md',
2018-02-09 04:47:47 +00:00
]
console.log(steps.map((value, index) => `${index + 1}. ${value}`).join('\n'))
2018-02-04 03:51:21 +00:00
}
export async function run(args: ReadonlyArray<string>): Promise<void> {
try {
await spawn('git', ['diff-index', '--quiet', 'HEAD'])
} catch {
throw new Error(
`There are uncommitted changes in the working directory. Aborting...`
)
}
if (args.length === 0) {
throw new Error(
`You have not specified a channel to draft this release for. Choose one of 'production' or 'beta'`
)
}
2018-02-04 01:15:29 +00:00
const channel = parseChannel(args[0])
const excludeBetaReleases = channel === 'production'
2018-02-09 04:04:30 +00:00
const previousVersion = await getLatestRelease({ excludeBetaReleases })
const nextVersion = getNextVersionNumber(previousVersion, channel)
const lines = await getLogLines(`release-${previousVersion}`)
const noChangesFound = lines.every(l => l.trim().length === 0)
if (noChangesFound) {
printInstructions(nextVersion, [])
} else {
const changelogEntries = await convertToChangelogFormat(lines)
console.log("Here's what you should do next:\n")
if (channel === 'production') {
const existingChangelog = getChangelogEntriesSince(previousVersion)
2018-08-01 21:51:59 +00:00
const entries = [...existingChangelog]
printInstructions(nextVersion, entries)
} else if (channel === 'beta') {
2018-08-01 21:51:59 +00:00
const entries = [...changelogEntries]
printInstructions(nextVersion, entries)
}
2018-02-04 03:51:21 +00:00
}
}