Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create new plugin : one-release-commit #2180

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ Auto has an extensive plugin system and wide variety of official plugins. Make a
- [microsoft-teams](./plugins/microsoft-teams) - Post your release notes to a Microsoft teams channel
- [omit-commits](./plugins/omit-commits) - Ignore commits base on name, email, subject, labels, and username
- [omit-release-notes](./plugins/omit-release-notes) - Ignore release notes in PRs made by certain accounts
- [one-release-commit](./plugins/one-release-commit) - Allow to create a single release commit
- [pr-body-labels](./plugins/pr-body-labels) - Allow outside contributors to indicate what semver label should be applied to the Pull Request
- [released](./plugins/released) - Add a `released` label to published PRs, comment with the version it's included in and comment on the issues the PR closes
- [s3](./plugins/s3) - Post your built artifacts to amazon s3
Expand Down
4 changes: 2 additions & 2 deletions docs/pages/docs/configuration/plugins.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ If you don't configure plugins in your `.autorc` configuration file `auto` will
- Installed through `npm` => uses [`npm`](../generated/npm)
- Installed through executable => uses [`git-tag`](../generated/git-tag)

For the majority of "package manager" plugins you should only use one at a time.
Using multiple _will_ lead to undesired results.
> :warning: For the majority of "package manager" plugins you should only use one at a time.
> Using multiple _will_ lead to undesired results.

### No Plugins

Expand Down
2 changes: 1 addition & 1 deletion docs/pages/docs/plugins/release-lifecycle-hooks.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ _Examples:_
- [brew](../generated/brew) - Create a new brew formula once the package a=has been versioned

```ts
auto.hooks.afterVersion.tapPromise("NPM", async ({ dryRun }) => {});
auto.hooks.afterVersion.tapPromise("NPM", async ({ dryRun, version }) => {});
```

## publish
Expand Down
112 changes: 76 additions & 36 deletions packages/core/src/auto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,17 @@ interface NextContext extends DryRunOption {
releaseNotes: string;
}

interface MakeReleaseContext extends DryRunOption {
/** Is current context stand for a pre-release */
isPrerelease: boolean;
/** Last release name like : "vx.y.z" */
lastRelease: string;
/** Commit to calculate the release to */
to?: string;
/** Version to release */
newVersion?: string;
}

type PublishResponse = RestEndpointMethodTypes["repos"]["createRelease"]["response"];

export interface IAutoHooks {
Expand Down Expand Up @@ -253,7 +264,10 @@ export interface IAutoHooks {
]
>;
/** Ran after the package has been versioned. */
afterVersion: AsyncSeriesHook<[DryRunOption]>;
afterVersion: AsyncSeriesHook<[DryRunOption & {
/** The version to release, if any */
version?: string;
}]>;
/** Publish the package to some package distributor. You must push the tags to github! */
publish: AsyncSeriesHook<
[
Expand Down Expand Up @@ -1214,7 +1228,13 @@ export default class Auto {
*/
async runRelease(options: IReleaseOptions = {}) {
this.logger.verbose.info("Using command: 'release'");
await this.makeRelease(options);

try {
const releasedVersion = await this.makeReleaseContext(options);
await this.makeRelease(releasedVersion);
} catch (e) {
this.logger.log.warn("Cannot proceed to release", e);
}
}

/** Create a canary (or test) version of the project */
Expand Down Expand Up @@ -1738,11 +1758,6 @@ export default class Auto {
return;
}

const lastRelease = options.from || (await this.git.getLatestRelease());
const commitsInRelease = await this.release.getCommitsInRelease(
lastRelease
);

await this.makeChangelog({
...options,
quiet: undefined,
Expand All @@ -1760,8 +1775,12 @@ export default class Auto {
dryRun: options.dryRun,
quiet: options.quiet,
});

// New new version must be computed, so make release context
const releaseArgs = await this.makeReleaseContext();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is problematic I think. For the default usage this would included the commit for the changelog in the release notes since it would now be in the commitsInRelease. Could you make sure this doesn't augment the normal auto workflow?

The changes below to for makeRelaeaseContext make sense and are good additions but the change in order has me worried.


this.logger.verbose.info("Calling after version hook");
await this.hooks.afterVersion.promise({ dryRun: options.dryRun });
await this.hooks.afterVersion.promise({ dryRun: options.dryRun, version: releaseArgs.newVersion });
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OH I see why you do all of this rearranging. in the afterVersion hook if it's not a dry run it IS a release. We don't have to care about the return value of makeRelease. The undefined that it returns is for it's other usage. Here we know a release (and thus a version) has happened.

You can revert all the changes to core and remove references in you plugin to version and it still all works!


if (!options.dryRun) {
this.logger.verbose.info("Calling publish hook");
Expand All @@ -1773,9 +1792,11 @@ export default class Auto {
await this.hooks.afterPublish.promise();
}

const release = await this.makeRelease(releaseArgs);

return {
newVersion: await this.makeRelease(options),
commitsInRelease,
newVersion: release?.newVersion,
commitsInRelease: release?.commitsInRelease || [],
context: "latest",
};
}
Expand Down Expand Up @@ -1945,12 +1966,16 @@ export default class Auto {
await this.hooks.afterChangelog.promise(context);
}

/** Make a release over a range of commits */
private async makeRelease(args: IReleaseOptions = {}) {
/** Retrieve the current releasing context */
private async makeReleaseContext(args: IReleaseOptions = {}): Promise<MakeReleaseContext> {
const options = { ...this.getCommandDefault("release"), ...args };
const { dryRun, from, to, useVersion, prerelease = false } = options;
const {
dryRun,
from,
to,
useVersion, prerelease = false } = options;

if (!this.release || !this.git) {
if (!this.git) {
throw this.createErrorMessage();
}

Expand All @@ -1961,24 +1986,26 @@ export default class Auto {
// tags indicates that something would definitely go wrong.
if (err?.message.includes("No names found") && !args.dryRun) {
this.logger.log.error(
endent`
endent`
Could not find any tags in the local repository. Exiting early.

The "release" command creates GitHub releases for tags that have already been created in your repo.

If there are no tags there is nothing to release. If you don't use "shipit" ensure you tag your releases with the new version number.
`,
"\n"
"\n"
);
this.logger.verbose.error(err);
return process.exit(1);
process.exit(1);
// Only for unit testing while process.exit is mocked
throw err;
}

const isPrerelease = prerelease || this.inPrereleaseBranch();
let lastRelease =
from ||
(isPrerelease && (await this.git.getPreviousTagInBranch())) ||
(await this.git.getLatestRelease());
from ||
(isPrerelease && (await this.git.getPreviousTagInBranch())) ||
(await this.git.getLatestRelease());

// Find base commit or latest release to generate the changelog to HEAD (new tag)
this.logger.veryVerbose.info(`Using ${lastRelease} as previous release.`);
Expand All @@ -1989,33 +2016,46 @@ export default class Auto {

this.logger.log.info('Current "Latest Release" on Github:', lastRelease);

const rawVersion =
useVersion ||
(isPrerelease && latestTag) ||
(await this.getCurrentVersion(lastRelease)) ||
latestTag;

if (!rawVersion) {
return { dryRun, to, lastRelease, newVersion: undefined, isPrerelease };
}

const newVersion = parse(rawVersion)
? this.prefixRelease(rawVersion)
: rawVersion;

return { dryRun, to, lastRelease, newVersion, isPrerelease };
}

/** Make a release over a range of commits */
private async makeRelease(makeReleaseContext: MakeReleaseContext) {
if (!this.release) {
throw this.createErrorMessage();
}

const { dryRun, to, lastRelease, newVersion, isPrerelease } = makeReleaseContext;
const commitsInRelease = await this.release.getCommitsInRelease(
lastRelease,
to
);

const releaseNotes = await this.release.generateReleaseNotes(
lastRelease,
to,
this.versionBump
);

this.logger.log.info(`Using release notes:\n${releaseNotes}`);

const rawVersion =
useVersion ||
(isPrerelease && latestTag) ||
(await this.getCurrentVersion(lastRelease)) ||
latestTag;

if (!rawVersion) {
if (!newVersion) {
this.logger.log.error("Could not calculate next version from last tag.");
return;
}

const newVersion = parse(rawVersion)
? this.prefixRelease(rawVersion)
: rawVersion;

if (
!dryRun &&
parse(newVersion) &&
Expand All @@ -2031,8 +2071,8 @@ export default class Auto {
const release = await this.hooks.makeRelease.promise({
dryRun,
from: lastRelease,
to: to || (await this.git.getSha()),
useVersion,
to: to || (await this.git!.getSha()),
useVersion: newVersion,
isPrerelease,
newVersion,
fullReleaseNotes: releaseNotes,
Expand All @@ -2049,7 +2089,7 @@ export default class Auto {
});
}

return newVersion;
return { newVersion, commitsInRelease };
}

/** Check if `git status` is clean. */
Expand Down
29 changes: 29 additions & 0 deletions plugins/one-release-commit/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# One-Release-Commit Plugin

Allow to create a single release commit
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Write a better description of why someone might want to use this plugin.


## Installation

This plugin is not included with the `auto` CLI installed via NPM. To install:

```bash
npm i --save-dev @auto-it/one-release-commit
# or
yarn add -D @auto-it/one-release-commit
```

## Usage

```json
{
"plugins": [
[
"one-release-commit",
{
// Release commit message
"commitMessage": ":rocket: New release is on the way :rocket:"
}
]
]
}
```