Skip to content

Commit

Permalink
Add ability to preview changelog in final format
Browse files Browse the repository at this point in the history
  • Loading branch information
t3chguy committed Sep 26, 2022
1 parent 5829de5 commit a5a1e0f
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 36 deletions.
28 changes: 17 additions & 11 deletions src/changelog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,20 +140,22 @@ export function makeChangeEntry(change: IChange, forProject: IProject): string {
return line;
}

function makeChangelogEntry(changes: IChange[], version: string, forProject: Project): string {
const formattedVersion = semver.parse(version).format(); // easy way of removing the leading 'v'
function makeChangelogEntry(changes: IChange[], version: string | null, forProject: Project): string {
const formattedVersion = version ? semver.parse(version).format() : null; // easy way of removing the leading 'v'
const now = new Date();

const lines = [];
const lines: string[] = [];

const padTwo = n => String(n).padStart(2, '0');
lines.push(`Changes in ` +
`[${formattedVersion}]` +
`(https://github.com/${forProject.owner}/${forProject.repo}/releases/tag/v${formattedVersion}) ` +
`(${now.getFullYear()}-${padTwo(now.getMonth()+1)}-${padTwo(now.getDate())})`,
);
lines.push('='.repeat(lines[0].length));
lines.push('');
if (version !== null) {
const padTwo = (n: number) => String(n).padStart(2, '0');
lines.push(`Changes in ` +
`[${formattedVersion}]` +
`(https://github.com/${forProject.owner}/${forProject.repo}/releases/tag/v${formattedVersion}) ` +
`(${now.getFullYear()}-${padTwo(now.getMonth()+1)}-${padTwo(now.getDate())})`,
);
lines.push('='.repeat(lines[0].length));
lines.push('');
}

const shouldInclude = changes.filter(c => c.shouldInclude);
const breaking = shouldInclude.filter(c => c.breaking);
Expand Down Expand Up @@ -218,6 +220,10 @@ function isPrereleaseFor(version: SemVer, forVersion: SemVer): boolean {
);
}

export async function previewChangelog(project: Project, changes: IChange[]) {
console.log(makeChangelogEntry(changes, null, project));
}

export async function updateChangelog(project: Project, changes: IChange[], forVersion: string) {
const forReleaseSemVer = semver.parse(forVersion);

Expand Down
76 changes: 51 additions & 25 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ limitations under the License.
*/

import log from 'loglevel';
import yargs from 'yargs/yargs';
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
import clc from 'cli-color';
import semver from 'semver';
Expand All @@ -31,7 +31,7 @@ import {
import { getLatestRelease, getReleaseBefore, getReleases, releasesContains } from "./releases";
import { ChangesByProject, getPackageJsonAtVersion, Project, branchExists, BranchMode } from './projects';
import { formatIssue } from './issue';
import { updateChangelog } from './changelog';
import { previewChangelog, updateChangelog } from './changelog';
import { Octokit } from '@octokit/rest';

function formatChangeType(changeType: ChangeType) {
Expand Down Expand Up @@ -74,21 +74,35 @@ function printChangeStatus(change: IChange, projectName: string, owner: string,
}

async function main() {
const args = yargs(hideBin(process.argv)).option('debug', {
alias: 'd',
type: 'boolean',
description: "Enable debug mode",
}).option('check', {
type: 'boolean',
description: "Don't update changelog, just output information on what changes would be included",
}).help().usage("Usage: $0 [-d] [--check] <version>").argv;

if (args._.length !== 1 && !args.check) {
const args = yargs(hideBin(process.argv)).version(false).options({
"debug": {
alias: 'd',
type: 'boolean',
description: "Enable debug mode",
},
"check": {
type: 'boolean',
description: "Don't update changelog, just output information on what changes would be included",
conflicts: ["preview"],
},
"preview": {
type: "boolean",
description: "Generate changelog as normal, but without version header and output to STDOUT.",
conflicts: ["check"],
},
}).command("* [version]", "Generate changelog for the given version", yargs => (
yargs.positional("version", {
description: "The version to generate the changelog for, " +
"required if --check and/or --preview are not specified.",
type: "string",
})
)).help().parseSync();

if (!args.version && !args.check && !args.preview) {
// Surely yargs should be able to do this? It seems incredibly confusing and I already regret using it
console.log("No version specified");
return;
}
const targetRelease = args._[0] as string;

if (args.debug) {
log.setLevel(log.levels.DEBUG);
Expand All @@ -109,26 +123,33 @@ async function main() {
let fromVer: string;
let toVer: string;

if (targetRelease) {
const targetReleaseSemVer = semver.parse(targetRelease);
if (args.version) {
const targetReleaseSemVer = semver.parse(args.version);
const targetIsPrerelease = targetReleaseSemVer.prerelease.length > 0;
const toVerReleaseBranch =
`release-v${targetReleaseSemVer.major}.${targetReleaseSemVer.minor}.${targetReleaseSemVer.patch}`;
if (releasesContains(rels, targetRelease)) {
log.debug("Found existing release for " + targetRelease);
if (releasesContains(rels, args.version)) {
log.debug("Found existing release for " + args.version);
// nb. getReleases only gets the most recent 100 so this won't work
// for older releases
fromVer = getReleaseBefore(rels, targetRelease, targetIsPrerelease).name;
toVer = targetRelease;
} else if (targetRelease !== 'develop' && await branchExists(dir, toVerReleaseBranch)) {
log.debug("Found release branch for " + targetRelease);
fromVer = getReleaseBefore(rels, args.version, targetIsPrerelease).name;
toVer = args.version;
} else if (args.version !== 'develop' && await branchExists(dir, toVerReleaseBranch)) {
log.debug("Found release branch for " + args.version);
// 'to' release has had a release branch cut but not yet a full release
// compare to the tip of the release branch
fromVer = getLatestRelease(rels, targetIsPrerelease).name;
toVer = toVerReleaseBranch;
branchMode = BranchMode.Release;
} else if (args.version !== 'develop' && await branchExists(dir, "staging")) {
log.debug("Found release branch for " + args.version);
// 'to' release has had a release branch cut but not yet a full release
// compare to the tip of the release branch
fromVer = getLatestRelease(rels, targetIsPrerelease).name;
toVer = "staging";
branchMode = BranchMode.Release;
} else {
log.debug("Found neither release nor branch for " + targetRelease);
log.debug("Found neither release nor branch for " + args.version);
// the 'to' release is an doesn't-yet-exist future release -
// compare to the tip of develop (a better piece of software
// might make this configurable...)
Expand Down Expand Up @@ -177,7 +198,7 @@ async function main() {

const numBreaking = allChanges.filter(c => c.breaking).length;
const numFeatures = allChanges.filter(c => c.changeType == ChangeType.FEATURE).length;
let suggestedBumpType;
let suggestedBumpType: "major" | "minor" | "patch";
if (numBreaking) {
suggestedBumpType = 'major';
} else if (numFeatures) {
Expand All @@ -193,8 +214,13 @@ async function main() {
return;
}

log.debug("Updating changelog entry for " + targetRelease);
await updateChangelog(project, allChanges, targetRelease);
if (args.preview) {
await previewChangelog(project, allChanges);
return;
}

log.debug("Updating changelog entry for " + args.version);
await updateChangelog(project, allChanges, args.version);
}

main();

0 comments on commit a5a1e0f

Please sign in to comment.