Skip to content

Commit

Permalink
Merge branch 'master' into release/v3
Browse files Browse the repository at this point in the history
  • Loading branch information
TheCleric committed Aug 25, 2020
2 parents 18b6d8e + b3cf419 commit 46182fc
Show file tree
Hide file tree
Showing 13 changed files with 911 additions and 114 deletions.
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,22 @@ If you specify both, `head` and `base`, it will be seen as an AND condition:
```

Note: If there are multiple rules matching one branch, all of the labels will be added to the PR. One example of this would be a configuration that contains the feature and subtask rules. If a new PR with `head` and `base` matching `feature/*` will be opened, the PR gets the labels `feature` AND `🧩 Subtask`.

You can also specify regular expressions:

```yaml
# Apply label "🧩 Subtask" if head and base match "feature/*"
🧩 Subtask:
headRegExp: 'feature[/].*'
baseRegExp: 'feature[/].*'
```

When using regular expressions you may also use group match numbers as labels:

```yaml
# Apply whatever comes after "release/" as the label when matching against base of "release/*"
$1:
baseRegExp: 'release[/](.*)'
```

In this example if you were merging into the `release/1.0.0` branch, the label `1.0.0` would be applied.
39 changes: 35 additions & 4 deletions __tests__/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,45 @@ describe("Config file loader", () => {

// Assert
expect(getConfigScope.isDone()).toBeTrue();
expect(config.length).toEqual(6);
expect(config.length).toEqual(11);
expect.assertions(2);
});

it("throws an error for an invalid config file", async () => {
it("converts regular expressions", async () => {
// Arrange
const getConfigScope = nock("https://api.github.com")
.persist()
.get("/repos/Codertocat/Hello-World/contents/.github/pr-branch-labeler.yml?ref=0123456")
.reply(200, configFixture());

const octokit = new github.GitHub("token");

const config = await getConfig(octokit, "pr-branch-labeler.yml", context);

const headRegExpConfigs = config.filter(x => x.headRegExp);
const headRegExpConfigsWithRegExp = headRegExpConfigs.filter(x =>
Array.isArray(x.headRegExp)
? x.headRegExp.map(x => x !== null && x.exec !== undefined).reduce((a, v) => a && v, true)
: x.headRegExp!.exec !== undefined
)

const baseRegExpConfigs = config.filter(x => x.baseRegExp);
const baseRegExpConfigsWithRegExp = baseRegExpConfigs.filter(x =>
Array.isArray(x.baseRegExp)
? x.baseRegExp.map(x => x !== null && x.exec !== undefined).reduce((a, v) => a && v, true)
: x.baseRegExp!.exec !== undefined
)

// Assert
expect(getConfigScope.isDone()).toBeTrue();
expect(headRegExpConfigs.length).toBeGreaterThan(0);
expect(headRegExpConfigs.length).toEqual(headRegExpConfigsWithRegExp.length);
expect(baseRegExpConfigs.length).toBeGreaterThan(0);
expect(baseRegExpConfigs.length).toEqual(baseRegExpConfigs.length);
expect.assertions(5);
});

it("throws an error for an invalid config file", async () => {
// Arrange
const getConfigScope = nock("https://api.github.com")
.persist()
Expand All @@ -60,7 +93,6 @@ describe("Config file loader", () => {
});

it("throws an error for a directory", async () => {

// Arrange
const getConfigScope = nock("https://api.github.com")
.persist()
Expand All @@ -77,7 +109,6 @@ describe("Config file loader", () => {
});

it("throws an error for no contents", async () => {

// Arrange
const getConfigScope = nock("https://api.github.com")
.persist()
Expand Down
302 changes: 302 additions & 0 deletions __tests__/configEntry.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,302 @@
import "jest-extended";
import nock from "nock";
import { ConfigEntry } from "../src/ConfigEntry";

nock.disableNetConnect();

describe("Config entry", () => {
let shared;

beforeEach(() => {
shared = require('./shared');
});

afterEach(() => {
nock.cleanAll();
});

describe("shorthand array", () => {
it("adds the 'support' label for 'support/FOO-42-assisting' to 'master'", async () => {

// Arrange
const entry = new ConfigEntry({ label: "support", head: ["support/*", "sup/*"] })

// Act
const label = entry.getLabel("support/FOO-42-assisting", "master");

// Assert
expect(label).toEqual("support");
expect.assertions(1);
});
});

describe("Regular head and base usage", () => {
it("adds the 'bugfix' label for 'bugfix/FOO-42-squash-bugs' to 'master'", async () => {
// Arrange
const entry = new ConfigEntry({ label: "bugfix", head: ["bugfix/*", "hotfix/*"] })

// Act
const label = entry.getLabel("bugfix/FOO-42-squash-bugs", "master");

// Assert
expect(label).toEqual("bugfix");
expect.assertions(1);
});

it("adds the 'bugfix' label for 'hotfix/FOO-42-squash-bugs' to 'master'", async () => {
// Arrange
const entry = new ConfigEntry({ label: "bugfix", head: ["bugfix/*", "hotfix/*"] })

// Act
const label = entry.getLabel("hotfix/FOO-42-squash-bugs", "master");

// Assert
expect(label).toEqual("bugfix");
expect.assertions(1);
});

it("adds the 'release' label for 'bugfix/FOO-42-changes' to 'release/1.0.0'", async () => {
// Arrange
const entry = new ConfigEntry({ label: "release", base: "release/*" })

// Act
const label = entry.getLabel("bugfix/FOO-42-changes", "release/1.0.0");

// Assert
expect(label).toEqual("release");
expect.assertions(1);
});

it("adds the '🧩 Subtask' label for 'feature/FOO-42-part' to 'feature/FOO-42-whole'", async () => {
// Arrange
const entry = new ConfigEntry({ label: "🧩 Subtask", head: "feature/*", base: "feature/*" })

// Act
const label = entry.getLabel("feature/FOO-42-part", "feature/FOO-42-whole");

// Assert
expect(label).toEqual("🧩 Subtask");
expect.assertions(1);
});

it("adds no labels if the branch doesn't match any patterns", async () => {
// Arrange
const entry = new ConfigEntry({ label: '' })

// Act
const label = entry.getLabel("fix-the-build", "master");

// Assert
expect(label).toEqual(undefined);
expect.assertions(1);
});
});

describe("Regular headRegExp and baseRegExp usage", () => {
it("adds the 'bugfix' label for 'bugfix/FOO-42-squash-bugs' to 'master'", async () => {
// Arrange
const entry = new ConfigEntry({ label: "bugfix", headRegExp: [/bugfix[/].*/, /hotfix[/].*/] })

// Act
const label = entry.getLabel("bugfix/FOO-42-squash-bugs", "master");

// Assert
expect(label).toEqual("bugfix");
expect.assertions(1);
});

it("adds the 'bugfix' label for 'hotfix/FOO-42-squash-bugs' to 'master'", async () => {
// Arrange
const entry = new ConfigEntry({ label: "bugfix", headRegExp: [/bugfix[/].*/, /hotfix[/].*/] })

// Act
const label = entry.getLabel("hotfix/FOO-42-squash-bugs", "master");

// Assert
expect(label).toEqual("bugfix");
expect.assertions(1);
});

it("adds the 'release' label for 'bugfix/FOO-42-changes' to 'release/1.0.0'", async () => {
// Arrange
const entry = new ConfigEntry({ label: "release", baseRegExp: /release[/].*/ })

// Act
const label = entry.getLabel("bugfix/FOO-42-changes", "release/1.0.0");

// Assert
expect(label).toEqual("release");
expect.assertions(1);
});

it("adds the '🧩 Subtask' label for 'feature/FOO-42-part' to 'feature/FOO-42-whole'", async () => {
// Arrange
const entry = new ConfigEntry({ label: "🧩 Subtask", headRegExp: /feature[/].*/, baseRegExp: /feature[/].*/ })

// Act
const label = entry.getLabel("feature/FOO-42-part", "feature/FOO-42-whole");

// Assert
expect(label).toEqual("🧩 Subtask");
expect.assertions(1);
});
});


describe("Regular headRegExp and baseRegExp usage", () => {
it("adds the 'bugfix' label for 'bugfix/FOO-42-squash-bugs' to 'master'", async () => {
// Arrange
const entry = new ConfigEntry({ label: "bugfix", headRegExp: [/bugfix[/].*/, /hotfix[/].*/] })

// Act
const label = entry.getLabel("bugfix/FOO-42-squash-bugs", "master");

// Assert
expect(label).toEqual("bugfix");
expect.assertions(1);
});

it("adds the 'bugfix' label for 'hotfix/FOO-42-squash-bugs' to 'master'", async () => {
// Arrange
const entry = new ConfigEntry({ label: "bugfix", headRegExp: [/bugfix[/].*/, /hotfix[/].*/] })

// Act
const label = entry.getLabel("hotfix/FOO-42-squash-bugs", "master");

// Assert
expect(label).toEqual("bugfix");
expect.assertions(1);
});

it("adds the 'release' label for 'bugfix/FOO-42-changes' to 'release/1.0.0'", async () => {
// Arrange
const entry = new ConfigEntry({ label: "release", baseRegExp: /release[/].*/ })

// Act
const label = entry.getLabel("bugfix/FOO-42-changes", "release/1.0.0");

// Assert
expect(label).toEqual("release");
expect.assertions(1);
});

it("adds the '🧩 Subtask' label for 'feature/FOO-42-part' to 'feature/FOO-42-whole'", async () => {
// Arrange
const entry = new ConfigEntry({ label: "🧩 Subtask", headRegExp: /feature[/].*/, baseRegExp: /feature[/].*/ })

// Act
const label = entry.getLabel("feature/FOO-42-part", "feature/FOO-42-whole");

// Assert
expect(label).toEqual("🧩 Subtask");
expect.assertions(1);
});
});


describe("Mixed regular and RegExp usage", () => {
it("adds the '🧩 Subtask' label for 'feature/FOO-42-part' to 'feature/FOO-42-whole' head to baseRegExp", async () => {
// Arrange
const entry = new ConfigEntry({ label: "🧩 Subtask", head: "feature/*", baseRegExp: /feature[/].*/ })

// Act
const label = entry.getLabel("feature/FOO-42-part", "feature/FOO-42-whole");

// Assert
expect(label).toEqual("🧩 Subtask");
expect.assertions(1);
});

it("adds the '🧩 Subtask' label for 'feature/FOO-42-part' to 'feature/FOO-42-whole' headRegExp to base", async () => {
// Arrange
const entry = new ConfigEntry({ label: "🧩 Subtask", headRegExp: /feature[/].*/, base: "feature/*" })

// Act
const label = entry.getLabel("feature/FOO-42-part", "feature/FOO-42-whole");

// Assert
expect(label).toEqual("🧩 Subtask");
expect.assertions(1);
});
});


describe("Dynamic headRegExp and baseRegExp usage", () => {
it("adds the 'FOO-42-squash-bugs' label for 'bugfix/FOO-42-squash-bugs' to 'master'", async () => {
// Arrange
const entry = new ConfigEntry({ label: "$1", headRegExp: [/bugfix[/](.*)/, /hotfix[/](.*)/] })

// Act
const label = entry.getLabel("bugfix/FOO-42-squash-bugs", "master");

// Assert
expect(label).toEqual("FOO-42-squash-bugs");
expect.assertions(1);
});

it("adds the 'FOO-42-squash-bugs' label for 'hotfix/FOO-42-squash-bugs' to 'master'", async () => {
// Arrange
const entry = new ConfigEntry({ label: "$1", headRegExp: [/bugfix[/].*/, /hotfix[/](.*)/] })

// Act
const label = entry.getLabel("hotfix/FOO-42-squash-bugs", "master");

// Assert
expect(label).toEqual("FOO-42-squash-bugs");
expect.assertions(1);
});

it("adds the '1.0.0' label for 'bugfix/FOO-42-changes' to 'release/1.0.0'", async () => {
// Arrange
const entry = new ConfigEntry({ label: "$1", baseRegExp: /release[/](.*)/ })

// Act
const label = entry.getLabel("bugfix/FOO-42-changes", "release/1.0.0");

// Assert
expect(label).toEqual("1.0.0");
expect.assertions(1);
});

it("adds the 'FOO-42-part' label for 'feature/FOO-42-part' to 'feature/FOO-42-whole'", async () => {
// Arrange
const entry = new ConfigEntry({ label: "$1", headRegExp: /feature[/](.*)/, baseRegExp: /feature[/](.*)/ })

// Act
const label = entry.getLabel("feature/FOO-42-part", "feature/FOO-42-whole");

// Assert
expect(label).toEqual("FOO-42-part");
expect.assertions(1);
});

it("adds the 'FOO-42-whole' label for 'feature/FOO-42-part' to 'feature/FOO-42-whole'", async () => {
// Arrange
const entry = new ConfigEntry({ label: "$2", headRegExp: /feature[/](.*)/, baseRegExp: /feature[/](.*)/ })

// Act
const label = entry.getLabel("feature/FOO-42-part", "feature/FOO-42-whole");

// Assert
expect(label).toEqual("FOO-42-whole");
expect.assertions(1);
});
});

describe("Disallows mixing of matching and regex for same branch", () => {
it("errors when using head and headRegExp", async () => {
// Assert
expect(() => { new ConfigEntry({ label: "bugfix", head: "bugfix/*", headRegExp: /bugfix[/].*/ }) })

.toThrow(new Error("Config can only contain one of: head, headRegExp"));
expect.assertions(1);
});

it("errors when using base and baseRegExp", async () => {
// Assert
expect(() => { new ConfigEntry({ label: "bugfix", base: "bugfix/*", baseRegExp: /bugfix[/].*/ }) })
.toThrow(new Error("Config can only contain one of: base, baseRegExp"))
expect.assertions(1);
});
});
});
Loading

0 comments on commit 46182fc

Please sign in to comment.