generated from salesforcecli/plugin-template
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add npm:release:validate command (#122)
* feat: add npm:release:validate command * chore: update topics
- Loading branch information
1 parent
01c59ae
commit 418ca2e
Showing
9 changed files
with
213 additions
and
95 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
/* | ||
* Copyright (c) 2020, salesforce.com, inc. | ||
* All rights reserved. | ||
* Licensed under the BSD 3-Clause license. | ||
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause | ||
*/ | ||
|
||
import { flags, FlagsConfig, SfdxCommand } from '@salesforce/command'; | ||
import { isMonoRepo, LernaRepo } from '../../../repository'; | ||
import { Package } from '../../../package'; | ||
import { CommitInspection, inspectCommits } from '../../../inspectCommits'; | ||
|
||
type PackageCommits = CommitInspection & { | ||
name: string; | ||
currentVersion: string; | ||
}; | ||
|
||
type Response = { | ||
shouldRelease: boolean; | ||
packages?: PackageCommits[]; | ||
}; | ||
|
||
export default class Validate extends SfdxCommand { | ||
public static readonly description = | ||
'inspects the git commits to see if there are any commits that will warrant a new release'; | ||
public static readonly flagsConfig: FlagsConfig = { | ||
verbose: flags.builtin({ | ||
description: 'show all commits for all packages (only works with --json flag)', | ||
}), | ||
}; | ||
|
||
public async run(): Promise<Response> { | ||
const isLerna = await isMonoRepo(); | ||
const packages = isLerna ? await LernaRepo.getPackages() : [await Package.create()]; | ||
const responses: PackageCommits[] = []; | ||
for (const pkg of packages) { | ||
const commitInspection = await inspectCommits(pkg, isLerna); | ||
const response = Object.assign(commitInspection, { | ||
name: pkg.name, | ||
currentVersion: pkg.packageJson.version, | ||
}); | ||
responses.push(response); | ||
} | ||
const shouldRelease = responses.some((resp) => !!resp.shouldRelease); | ||
this.ux.log(shouldRelease.toString()); | ||
return this.flags.verbose ? { shouldRelease, packages: responses } : { shouldRelease }; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
/* | ||
* Copyright (c) 2020, salesforce.com, inc. | ||
* All rights reserved. | ||
* Licensed under the BSD 3-Clause license. | ||
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause | ||
*/ | ||
|
||
import * as os from 'os'; | ||
import { Readable } from 'stream'; | ||
import { exec } from 'shelljs'; | ||
import * as conventionalCommitsParser from 'conventional-commits-parser'; | ||
import * as conventionalChangelogPresetLoader from 'conventional-changelog-preset-loader'; | ||
import { Nullable } from '@salesforce/ts-types'; | ||
import { Package } from './package'; | ||
|
||
export interface Commit { | ||
type: Nullable<string>; | ||
header: Nullable<string>; | ||
body: Nullable<string>; | ||
} | ||
|
||
export interface CommitInspection { | ||
releasableCommits: Commit[]; | ||
unreleasableCommits: Commit[]; | ||
nextVersionIsHardcoded: boolean; | ||
shouldRelease: boolean; | ||
} | ||
|
||
/** | ||
* If the commit type isn't fix (patch bump), feat (minor bump), or breaking (major bump), | ||
* then standard-version always defaults to a patch bump. | ||
* See https://github.com/conventional-changelog/standard-version/issues/577 | ||
* | ||
* We, however, don't want to publish a new version for chore, docs, etc. So we analyze | ||
* the commits to see if any of them indicate that a new release should be published. | ||
*/ | ||
export async function inspectCommits(pkg: Package, lerna = false): Promise<CommitInspection> { | ||
const skippableCommitTypes = ['chore', 'style', 'docs', 'ci', 'test']; | ||
|
||
// find the latest git tag so that we can get all the commits that have happened since | ||
const tags = exec('git fetch --tags && git tag', { silent: true }).stdout.split(os.EOL); | ||
const latestTag = lerna | ||
? tags.find((tag) => tag.includes(`${pkg.name}@${pkg.npmPackage.version}`)) || '' | ||
: tags.find((tag) => tag.includes(pkg.npmPackage.version)); | ||
// import the default commit parser configuration | ||
const defaultConfigPath = require.resolve('conventional-changelog-conventionalcommits'); | ||
const configuration = await conventionalChangelogPresetLoader({ name: defaultConfigPath }); | ||
|
||
const commits: Commit[] = await new Promise((resolve) => { | ||
const DELIMITER = 'SPLIT'; | ||
const gitLogCommand = lerna | ||
? `git log --format=%B%n-hash-%n%H%n${DELIMITER} ${latestTag}..HEAD --no-merges -- ${pkg.location}` | ||
: `git log --format=%B%n-hash-%n%H%n${DELIMITER} ${latestTag}..HEAD --no-merges`; | ||
const gitLog = exec(gitLogCommand, { silent: true }) | ||
.stdout.split(`${DELIMITER}${os.EOL}`) | ||
.filter((c) => !!c); | ||
const readable = Readable.from(gitLog); | ||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
// @ts-ignore because the type exported from conventionalCommitsParser is wrong | ||
const parser = readable.pipe(conventionalCommitsParser(configuration.parserOpts)); | ||
const allCommits: Commit[] = []; | ||
parser.on('data', (commit: Commit) => allCommits.push(commit)); | ||
parser.on('finish', () => resolve(allCommits)); | ||
}); | ||
|
||
const nextVersionIsHardcoded = pkg.nextVersionIsHardcoded(); | ||
// All commits are releasable if the version hardcoded in the package.json | ||
// In this scenario, we want to publish regardless of the commit types | ||
if (nextVersionIsHardcoded) { | ||
return { | ||
releasableCommits: commits, | ||
unreleasableCommits: [], | ||
nextVersionIsHardcoded, | ||
shouldRelease: true, | ||
}; | ||
} | ||
|
||
const releasableCommits: Commit[] = []; | ||
const unreleasableCommits: Commit[] = []; | ||
for (const commit of commits) { | ||
const headerIndicatesMajorChange = !!commit.header && commit.header.includes('!'); | ||
const bodyIndicatesMajorChange = !!commit.body && commit.body.includes('BREAKING'); | ||
const typeIsSkippable = skippableCommitTypes.includes(commit.type); | ||
const isReleasable = !typeIsSkippable || bodyIndicatesMajorChange || headerIndicatesMajorChange; | ||
if (isReleasable) { | ||
releasableCommits.push(commit); | ||
} else { | ||
unreleasableCommits.push(commit); | ||
} | ||
} | ||
|
||
return { | ||
releasableCommits, | ||
unreleasableCommits, | ||
nextVersionIsHardcoded, | ||
shouldRelease: nextVersionIsHardcoded || releasableCommits.length > 0, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.