Skip to content

Commit

Permalink
Merge pull request #1554 from intuit/pr-label-body
Browse files Browse the repository at this point in the history
Add pr-body-labels plugin
  • Loading branch information
hipstersmoothie authored Oct 1, 2020
2 parents beb6ea1 + 109658c commit c9d0b51
Show file tree
Hide file tree
Showing 15 changed files with 277 additions and 8 deletions.
21 changes: 21 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,23 @@ jobs:
- attach_workspace:
at: ~/auto
- run: *lint
- run:
name: Release
command: yarn auto pr-check --url $CIRCLE_PULL_REQUEST

pr-check:
<<: *defaults
steps:
- attach_workspace:
at: ~/auto
- run:
name: Check for SemVer Label
command: |
if [ ! -z "$CIRCLE_PR_NUMBER" ]; then
yarn auto pr-check --url $CIRCLE_PULL_REQUEST
else
echo "No pull request, not checking for semver label"
fi
test:
<<: *defaults
Expand Down Expand Up @@ -100,6 +117,10 @@ workflows:
requires:
- install

- pr-check:
requires:
- build

- lint:
requires:
- build
Expand Down
11 changes: 10 additions & 1 deletion .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
# What Changed

# Why
## Why

Todo:

- [ ] Add tests
- [ ] Add docs

## Change Type

Indicate the type of change your pull request is:

- [ ] `documentation`
- [ ] `patch`
- [ ] `minor`
- [ ] `major`
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ Auto has an extensive plugin system and wide variety of official plugins. Make a
- [jira](./plugins/jira) - Include Jira story links in the changelog
- [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
- [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
- [slack](./plugins/slack) - Post release notes to slack
Expand Down
1 change: 1 addition & 0 deletions docs/pages/docs/_sidebar.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ Functionality Plugins
- [Jira](./generated/jira)
- [Omit Commits](./generated/omit-commits)
- [Omit Release Notes](./generated/omit-release-notes)
- [PR Body Labels](./generated/pr-body-labels)
- [Released](./generated/released)
- [Slack](./generated/slack)
- [Twitter](./generated/twitter)
Expand Down
15 changes: 15 additions & 0 deletions docs/pages/docs/plugins/release-lifecycle-hooks.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ title: Release Lifecycle Hooks
The following hooks are all called during various release commands (ex: `latest`, `next`, `canary`, `shipit`).
These hooks is where the publishing of your package actually happens.

- [prCheck](#prCheck)
- [beforeShipIt](#beforeshipit)
- [beforeCommitChangelog](#beforecommitchangelog)
- [afterAddToChangelog](#afteraddtochangelog)
Expand All @@ -18,6 +19,20 @@ These hooks is where the publishing of your package actually happens.
- [afterRelease](#afterrelease)
- [afterShipIt](#aftershipit)

## prCheck

Called before `auto pr-check` is ran/

Context Object:

- `pr` - All github information related to the PR

```ts
auto.hooks.prCheck.tapPromise("NPM", async ({ pr }) => {
// Do stuff
});
```

## beforeShipIt

Happens before `shipit` is run.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
],
"scripts": {
"clean": "lerna clean --yes && rimraf node_modules '+(packages|plugins)/**/+(dist|tsconfig.tsbuildinfo)'",
"semver:check": "./scripts/post-install.sh",
"build": "tsc -b tsconfig.dev.json",
"start": "npm run build -- --watch",
"lint": "eslint packages plugins --ext .ts --cache",
Expand Down Expand Up @@ -139,6 +138,7 @@
],
"released",
"first-time-contributor",
"pr-body-labels",
"./scripts/auto-update-curl-version.js",
[
"all-contributors",
Expand Down
11 changes: 11 additions & 0 deletions packages/core/src/auto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,15 @@ export interface IAutoHooks {
next: AsyncSeriesWaterfallHook<[string[], SEMVER, NextContext]>;
/** Ran after the package has been published. */
afterPublish: AsyncParallelHook<[]>;
/** Ran after the package has been published. */
prCheck: AsyncSeriesHook<
[
{
/** The complete information about the PR */
pr: RestEndpointMethodTypes["pulls"]["get"]["response"]["data"];
}
]
>;
}

/** Load the .env file into process.env. Useful for local usage. */
Expand Down Expand Up @@ -875,6 +884,8 @@ export default class Auto {

try {
const res = await this.git.getPullRequest(prNumber);
await this.hooks.prCheck.promise({ pr: res.data });

sha = res.data.head.sha;

const labels = await this.git.getLabels(prNumber);
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/utils/make-hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export const makeHooks = (): IAutoHooks => ({
getAuthor: new AsyncSeriesBailHook(),
getPreviousVersion: new AsyncSeriesBailHook(),
getRepository: new AsyncSeriesBailHook(),
prCheck: new AsyncSeriesBailHook(['prInformation']),
version: new AsyncParallelHook(["version"]),
afterVersion: new AsyncParallelHook(),
publish: new AsyncParallelHook(["version"]),
Expand Down
51 changes: 51 additions & 0 deletions plugins/pr-body-labels/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Pr-Body-Labels Plugin

Allow outside contributors to indicate what semver label should be applied to the Pull Request.

## Installation

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

```bash
npm i --save-dev @auto-it/pr-body-labels
# or
yarn add -D @auto-it/pr-body-labels
```

## Usage

```json
{
"plugins": [
["pr-body-labels"]
// other plugins
]
}
```

Then something like the following to your `.github/PULL_REQUEST_TEMPLATE.md`.
The only part of this that really matters is a markdown checkbox + one of your labels.
You control what labels an outside contributor can apply through the PR body.
This example only exposes the semantic versioning labels but you can include any label in your project.

```md
## Change Type

Indicate the type of change your pull request is:

- [ ] `patch`
- [ ] `minor`
- [ ] `major`
```

## Options

### `disabledLabels`

Labels the user cannot apply through the PR.

```json
{
"plugins": [["pr-body-labels", { "disabledLabels": ["release"] }]]
}
```
56 changes: 56 additions & 0 deletions plugins/pr-body-labels/__tests__/pr-body-labels.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { makeHooks } from "@auto-it/core/dist/utils/make-hooks";

import PrBodyLabels from "../src";

describe("Pr-Body-Labels Plugin", () => {
test("not add labels not present in project", async () => {
const plugin = new PrBodyLabels();
const hooks = makeHooks();
const addLabelToPr = jest.fn();

plugin.apply({
hooks,
labels: [],
git: { addLabelToPr },
} as any);

await hooks.prCheck.promise({
pr: { body: "- [x] `unknown-label`" },
} as any);
expect(addLabelToPr).not.toHaveBeenCalled();
});

test("add labels present in project", async () => {
const plugin = new PrBodyLabels();
const hooks = makeHooks();
const addLabelToPr = jest.fn();

plugin.apply({
hooks,
labels: [{ name: "patch" }],
git: { addLabelToPr },
} as any);

await hooks.prCheck.promise({
pr: { body: "- [x] `patch`", number: 1 },
} as any);
expect(addLabelToPr).toHaveBeenCalledWith(1, "patch");
});

test("not add labels in disabledLabels list", async () => {
const plugin = new PrBodyLabels({ disabledLabels: ["patch"] });
const hooks = makeHooks();
const addLabelToPr = jest.fn();

plugin.apply({
hooks,
labels: [{ name: "patch" }],
git: { addLabelToPr },
} as any);

await hooks.prCheck.promise({
pr: { body: "- [x] `patch`", number: 1 },
} as any);
expect(addLabelToPr).not.toHaveBeenCalled();
});
});
44 changes: 44 additions & 0 deletions plugins/pr-body-labels/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"name": "@auto-it/pr-body-labels",
"version": "9.53.1",
"main": "dist/index.js",
"description": "Allow outside contributors to indicate what semver label should be applied to the Pull Request",
"license": "MIT",
"author": {
"name": "Andrew Lisowski",
"email": "lisowski54@gmail.com"
},
"publishConfig": {
"registry": "https://registry.npmjs.org/",
"access": "public"
},
"repository": {
"type": "git",
"url": "https://github.com/intuit/auto"
},
"files": [
"dist"
],
"keywords": [
"automation",
"semantic",
"release",
"github",
"labels",
"automated",
"continuos integration",
"changelog"
],
"scripts": {
"build": "tsc -b",
"start": "npm run build -- -w",
"lint": "eslint src --ext .ts",
"test": "jest --maxWorkers=2 --config ../../package.json"
},
"dependencies": {
"@auto-it/core": "link:../../packages/core",
"fp-ts": "^2.5.3",
"io-ts": "^2.1.2",
"tslib": "1.10.0"
}
}
45 changes: 45 additions & 0 deletions plugins/pr-body-labels/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Auto, IPlugin } from "@auto-it/core";
import * as t from "io-ts";

const pluginOptions = t.partial({
/** Labels the user cannot apply through the PR */
disabledLabels: t.array(t.string),
});

export type IPrBodyLabelsPluginOptions = t.TypeOf<typeof pluginOptions>;

/** Allow outside contributors to indicate what semver label should be applied to the Pull Request */
export default class PrBodyLabelsPlugin implements IPlugin {
/** The name of the plugin */
name = "pr-body-labels";

/** The options of the plugin */
private readonly options: Required<IPrBodyLabelsPluginOptions>;

/** Initialize the plugin with it's options */
constructor(options: IPrBodyLabelsPluginOptions = {}) {
this.options = {
disabledLabels: options.disabledLabels || [],
};
}

/** Tap into auto plugin points. */
apply(auto: Auto) {
auto.hooks.prCheck.tapPromise(this.name, async ({ pr }) => {
if (!auto.git || !auto.labels) {
return;
}

await Promise.all(
auto.labels.map(async (label) => {
if (
pr.body.includes(`- [x] \`${label.name}\``) &&
!this.options.disabledLabels.includes(label.name)
) {
await auto.git?.addLabelToPr(pr.number, label.name);
}
})
);
});
}
}
16 changes: 16 additions & 0 deletions plugins/pr-body-labels/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"extends": "../../tsconfig.json",
"include": ["src/**/*", "../../typings/**/*"],

"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src",
"composite": true
},

"references": [
{
"path": "../../packages/core"
}
]
}
5 changes: 0 additions & 5 deletions scripts/post-install.sh

This file was deleted.

5 changes: 4 additions & 1 deletion tsconfig.dev.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@
},
{
"path": "plugins/docker"
},
{
"path": "plugins/pr-body-labels"
}
]
}
}

0 comments on commit c9d0b51

Please sign in to comment.