Skip to content

Commit

Permalink
feat: add support for objects in arrays in the payload filter (#589)
Browse files Browse the repository at this point in the history
* feat: add support for objects in arrays in the payload filter

* chore: restore old package lock file

* chore: add changelog entry and usage documentation

* chore: throw error if key required but not provided
  • Loading branch information
jaredhobbs committed Sep 27, 2021
1 parent bb5034a commit 14caa46
Show file tree
Hide file tree
Showing 5 changed files with 219 additions and 8 deletions.
172 changes: 171 additions & 1 deletion __tests__/unit/filters/payload.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ test('that checks are done against correct field', async () => {
expect(filter.status).toBe('fail')
})

test('that proper errors are returned if the field does not exit', async () => {
test('that proper errors are returned if the field does not exist', async () => {
const payload = new Payload()

const settings = {
Expand Down Expand Up @@ -77,3 +77,173 @@ test('that proper errors are returned if the field does not exit', async () => {
const filter = await payload.processFilter(context, settings)
expect(filter.status).toBe('error')
})

test('that checks work against objects in an array with must_include', async () => {
const payload = new Payload()

const settings = {
do: 'payload',
pull_request: {
labels: {
must_include: {
regex: 'foo',
key: 'name'
}
}
}
}

let context = {
payload: {
repository: {
full_name: 'test-repo'
},
pull_request: {
labels: [
{
name: 'foo'
}
]
}
}
}

let filter = await payload.processFilter(context, settings)
expect(filter.status).toBe('pass')

context = {
payload: {
repository: {
full_name: 'test-repo'
},
pull_request: {
labels: [
{
name: 'bar'
}
]
}
}
}

filter = await payload.processFilter(context, settings)
expect(filter.status).toBe('fail')
})

test('that checks work against objects in an array with must_exclude', async () => {
const payload = new Payload()

const settings = {
do: 'payload',
pull_request: {
labels: {
must_exclude: {
regex: 'foo',
key: 'name'
}
}
}
}

let context = {
payload: {
repository: {
full_name: 'test-repo'
},
pull_request: {
labels: [
{
name: 'bar'
}
]
}
}
}

let filter = await payload.processFilter(context, settings)
expect(filter.status).toBe('pass')

context = {
payload: {
repository: {
full_name: 'test-repo'
},
pull_request: {
labels: [
{
name: 'foo'
}
]
}
}
}

filter = await payload.processFilter(context, settings)
expect(filter.status).toBe('fail')
})

test('that proper errors are returned if a key is required but not provided in must_include', async () => {
const payload = new Payload()

const settings = {
do: 'payload',
pull_request: {
labels: {
must_include: {
regex: 'foo'
}
}
}
}

const context = {
payload: {
repository: {
full_name: 'test-repo'
},
pull_request: {
labels: [
{
name: 'foo'
}
]
}
}
}

const filter = await payload.processFilter(context, settings)
expect(filter.status).toBe('error')
})

test('that proper errors are returned if a key is required but not provided in must_exclude', async () => {
const payload = new Payload()

const settings = {
do: 'payload',
pull_request: {
labels: {
must_exclude: {
regex: 'foo'
}
}
}
}

const context = {
payload: {
repository: {
full_name: 'test-repo'
},
pull_request: {
labels: [
{
name: 'bar'
}
]
}
}
}

const filter = await payload.processFilter(context, settings)
expect(filter.status).toBe('error')
})
1 change: 1 addition & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
CHANGELOG
=====================================
| September 25, 2021: feat: Support for objects in arrays in the payload filter `#589 <https://github.com/mergeability/mergeable/pull/589>`_
| September 20, 2021 : fix: Check that getRouter is defined before attempting to access it `#587 <https://github.com/mergeability/mergeable/pull/587>`_
| August 26, 2021 : fix: Await GithubAPI topics response `#585 <https://github.com/mergeability/mergeable/pull/585>`_
| August 10, 2021 : feat: New labels API `#577 <https://github.com/mergeability/mergeable/pull/577>`_
Expand Down
20 changes: 17 additions & 3 deletions docs/filters/payload.rst
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
Payload
^^^^^^^^^^^^^^

Check against any available fields within the payload, each event can have different field, please refer to `github API documentation for<https://docs.github.com/en/developers/webhooks-and-events/webhook-events-and-payloads>`_ available fields.
Check against any available fields within the payload, each event can have different field, please refer to `github API documentation for <https://docs.github.com/en/developers/webhooks-and-events/webhook-events-and-payloads>`_ for available fields.

An example to check if a pull_request_review event has `state` of `changes_requested`

.. codeblock:: yml
::

- do: payload
review:
Expand All @@ -14,16 +14,30 @@ An example to check if a pull_request_review event has `state` of `changes_reque
regex: 'changes_requested'


An example to check if a pull_request event has a `label` named `foo`

::

- do: payload
pull_request:
labels:
must_include:
regex: 'foo'
key: 'name'


Each field must be checked using one of the following options

.. codeblock:: yml
::

must_include:
regex: 'This text must be included'
regex_flag: 'none' # Optional. Specify the flag for Regex. default is 'i', to disable default use 'none'
key: 'name' # Optional. If checking an array of objects, this specifies the key to check.
must_exclude:
regex: 'Text to exclude'
regex_flag: 'none' # Optional. Specify the flag for Regex. default is 'i', to disable default use 'none'
key: 'name' # Optional. If checking an array of objects, this specifies the key to check.


Supported Events:
Expand Down
20 changes: 18 additions & 2 deletions lib/validators/options_processor/options/must_exclude.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
const REGEX_NOT_FOUND_ERROR = 'Failed to run the test because \'regex\' is not provided for \'must_exclude\' option. Please check README for more information about configuration'
const UNKNOWN_INPUT_TYPE_ERROR = 'Input type invalid, expected either string or array of string as input'
const KEY_NOT_FOUND_ERROR = 'Input type is an object and requires providing a \'key\' for the \'must_exclude\' option.'

class MustExclude {
static process (validatorContext, input, rule) {
const filter = rule.must_exclude

const regex = filter.regex
const key = filter.key
let description = filter.message
if (!regex) {
throw new Error(REGEX_NOT_FOUND_ERROR)
Expand Down Expand Up @@ -34,9 +36,23 @@ class MustExclude {
return !regexObj.test(input)
} else if (Array.isArray(input)) {
if (filter.all) {
return input.every(label => !regexObj.test(label))
return input.every(label => {
if (typeof label === 'string') {
return !regexObj.test(label)
} else if (key) {
return !regexObj.test(label[key])
}
throw new Error(KEY_NOT_FOUND_ERROR)
})
} else {
return !input.some(label => regexObj.test(label))
return !input.some(label => {
if (typeof label === 'string') {
return regexObj.test(label)
} else if (key) {
return regexObj.test(label[key])
}
throw new Error(KEY_NOT_FOUND_ERROR)
})
}
} else {
throw new Error(UNKNOWN_INPUT_TYPE_ERROR)
Expand Down
14 changes: 12 additions & 2 deletions lib/validators/options_processor/options/must_include.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
const REGEX_NOT_FOUND_ERROR = 'Failed to run the test because \'regex\' is not provided for \'must_include\' option. Please check README for more information about configuration'
const UNKNOWN_INPUT_TYPE_ERROR = 'Input type invalid, expected either string or array of string as input'
const KEY_NOT_FOUND_ERROR = 'Input type is an object and requires providing a \'key\' for the \'must_include\' option.'

class MustInclude {
static process (validatorContext, input, rule) {
const filter = rule.must_include

const regex = filter.regex
const key = filter.key
let description = filter.message
if (!regex) {
throw new Error(REGEX_NOT_FOUND_ERROR)
Expand Down Expand Up @@ -33,10 +35,18 @@ class MustInclude {
if (typeof input === 'string') {
return regexObj.test(input)
} else if (Array.isArray(input)) {
const arrayHandler = label => {
if (typeof label === 'string') {
return regexObj.test(label)
} else if (key) {
return regexObj.test(label[key])
}
throw new Error(KEY_NOT_FOUND_ERROR)
}
if (filter.all) {
return input.every(label => regexObj.test(label))
return input.every(arrayHandler)
} else {
return input.some(label => regexObj.test(label))
return input.some(arrayHandler)
}
} else {
throw new Error(UNKNOWN_INPUT_TYPE_ERROR)
Expand Down

0 comments on commit 14caa46

Please sign in to comment.