diff --git a/src/bin/release-please.ts b/src/bin/release-please.ts index 9e955c4b5..7b43e566e 100644 --- a/src/bin/release-please.ts +++ b/src/bin/release-please.ts @@ -54,6 +54,9 @@ const argv = yargs describe: 'name of package release is being minted for', demand: true, }) + .option('version-file', { + describe: 'path to version file to update, e.g., version.rb', + }) .option('last-package-version', { describe: 'last version # that package was released as', }) @@ -163,6 +166,7 @@ action "github-release" { 'java-auth-yoshi', 'java-yoshi', 'python', + 'ruby', 'ruby-yoshi', ], default: 'node', diff --git a/src/release-pr-factory.ts b/src/release-pr-factory.ts index 16ad3c3bc..45039e4c8 100644 --- a/src/release-pr-factory.ts +++ b/src/release-pr-factory.ts @@ -20,6 +20,7 @@ import { ReleasePR, ReleasePROptions, } from './release-pr'; +import { Ruby, RubyReleasePROptions } from './releasers/ruby'; import { JavaAuthYoshi } from './releasers/java-auth-yoshi'; import { Node } from './releasers/node'; import { PHPYoshi } from './releasers/php-yoshi'; @@ -45,6 +46,8 @@ export class ReleasePRFactory { return new JavaYoshi(releaseOptions); case ReleaseType.Python: return new Python(releaseOptions); + case ReleaseType.Ruby: + return new Ruby(releaseOptions as RubyReleasePROptions); case ReleaseType.RubyYoshi: return new RubyYoshi(releaseOptions); default: diff --git a/src/release-pr.ts b/src/release-pr.ts index f405967d8..a43b03bb4 100644 --- a/src/release-pr.ts +++ b/src/release-pr.ts @@ -31,6 +31,7 @@ export enum ReleaseType { JavaAuthYoshi = 'java-auth-yoshi', JavaYoshi = 'java-yoshi', Python = 'python', + Ruby = 'ruby', RubyYoshi = 'ruby-yoshi', } diff --git a/src/releasers/ruby.ts b/src/releasers/ruby.ts new file mode 100644 index 000000000..339a0cb2d --- /dev/null +++ b/src/releasers/ruby.ts @@ -0,0 +1,112 @@ +/** + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ReleasePROptions, ReleasePR, ReleaseCandidate } from '../release-pr'; + +import { ConventionalCommits } from '../conventional-commits'; +import { GitHubTag } from '../github'; +import { checkpoint, CheckpointType } from '../util/checkpoint'; +import { indentCommit } from '../util/indent-commit'; +import { Update } from '../updaters/update'; +import { Commit } from '../graphql-to-commits'; + +// Generic +import { Changelog } from '../updaters/changelog'; + +// Ruby +import { VersionRB } from '../updaters/version-rb'; + +export interface RubyReleasePROptions extends ReleasePROptions { + // should be full path to version.rb file. + versionFile: string; +} + +export class Ruby extends ReleasePR { + versionFile: string; + constructor(options: RubyReleasePROptions) { + super(options as ReleasePROptions); + this.versionFile = options.versionFile; + } + protected async _run() { + const latestTag: GitHubTag | undefined = await this.gh.latestTag(); + const commits: Commit[] = await this.commits( + latestTag ? latestTag.sha : undefined + ); + + const cc = new ConventionalCommits({ + commits: postProcessCommits(commits), + githubRepoUrl: this.repoUrl, + bumpMinorPreMajor: this.bumpMinorPreMajor, + }); + const candidate: ReleaseCandidate = await this.coerceReleaseCandidate( + cc, + latestTag + ); + + const changelogEntry: string = await cc.generateChangelogEntry({ + version: candidate.version, + currentTag: `v${candidate.version}`, + previousTag: candidate.previousTag, + }); + + // don't create a release candidate until user facing changes + // (fix, feat, BREAKING CHANGE) have been made; a CHANGELOG that's + // one line is a good indicator that there were no interesting commits. + if (this.changelogEmpty(changelogEntry)) { + checkpoint( + `no user facing commits found since ${ + latestTag ? latestTag.sha : 'beginning of time' + }`, + CheckpointType.Failure + ); + return; + } + + const updates: Update[] = []; + + updates.push( + new Changelog({ + path: 'CHANGELOG.md', + changelogEntry, + version: candidate.version, + packageName: this.packageName, + }) + ); + + updates.push( + new VersionRB({ + path: this.versionFile, + changelogEntry, + version: candidate.version, + packageName: this.packageName, + }) + ); + + await this.openPR( + commits[0].sha!, + `${changelogEntry}\n---\n`, + updates, + candidate.version + ); + } +} + +function postProcessCommits(commits: Commit[]): Commit[] { + commits.forEach(commit => { + commit.message = indentCommit(commit); + }); + return commits; +}