forked from mirrors/probot
commit
a26d96ba27
|
@ -82,13 +82,16 @@ if @issue.body contains "- [ ]"
|
|||
#### Operations
|
||||
|
||||
Operator | Description | Example
|
||||
------------|-------------------------------|-----------------------------------
|
||||
--------------------|-------------------------------------|-----------------------------------
|
||||
`is` | equal | `@sender.login is "hubot"`
|
||||
`is not` | not equal | `@sender.login is not "hubot"`
|
||||
`contains` | string contains a substring | `@issue.body contains "- [ ]"`
|
||||
`does not contain` | string does not contain a substring | `@issue.body does not contain "- [x]"`
|
||||
`matches` | matches a regular expression | `@issue.title matches "^\[?WIP\]?"`
|
||||
`does not match` | does not match a regular expression | `@issue.title does not match "v\d+\.\d+"`
|
||||
`and` | logical and | `labeled(bug) and @sender.login is "hubot"`
|
||||
`or` | logical or | `labeled(bug) or labeled(defect)`
|
||||
`not` | negate a condition | `not labeled(bug)`
|
||||
|
||||
#### Functions
|
||||
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
const operators = {
|
||||
'is': (left, right) => left === right,
|
||||
'is not': (left, right) => left !== right,
|
||||
'or': (left, right) => left || right,
|
||||
'and': (left, right) => left && right,
|
||||
'contains': (left, right) => left.includes(right),
|
||||
'matches': (left, right) => left.match(right)
|
||||
'does not contain': (left, right) => !left.includes(right),
|
||||
'matches': (left, right) => left.match(right),
|
||||
'does not match': (left, right) => !left.match(right),
|
||||
'or': (left, right) => left || right,
|
||||
'and': (left, right) => left && right
|
||||
};
|
||||
|
||||
function resolve(value, context) {
|
||||
|
|
|
@ -71,7 +71,13 @@ RelationalExpression
|
|||
= head:LogicalOrExpression tail:(ws RelationalOperator ws LogicalOrExpression)* {
|
||||
return logicalExpression(head, tail);
|
||||
}
|
||||
RelationalOperator = "is not" / "is" / "contains" / "matches"
|
||||
RelationalOperator
|
||||
= "is not"
|
||||
/ "is"
|
||||
/ "does not contain"
|
||||
/ "contains"
|
||||
/ "does not match"
|
||||
/ "matches"
|
||||
|
||||
LogicalOrExpression
|
||||
= head:LogicalAndExpression tail:(ws or ws LogicalAndExpression)* {
|
||||
|
@ -79,10 +85,21 @@ LogicalOrExpression
|
|||
}
|
||||
|
||||
LogicalAndExpression
|
||||
= head:operand tail:(ws and ws operand)* {
|
||||
= head:UnaryExpression tail:(ws and ws UnaryExpression)* {
|
||||
return logicalExpression(head, tail);
|
||||
}
|
||||
|
||||
UnaryExpression
|
||||
= operand
|
||||
/ operator:UnaryOperator ws argument:UnaryExpression {
|
||||
return {
|
||||
type: 'UnaryExpression',
|
||||
operator: operator,
|
||||
argument: argument
|
||||
}
|
||||
}
|
||||
UnaryOperator = "not"
|
||||
|
||||
operand = condition / attribute / string / boolean
|
||||
|
||||
condition
|
||||
|
|
|
@ -62,4 +62,10 @@ module.exports = class Transformer {
|
|||
return logicalExpression(context, node.left, node.operator, node.right);
|
||||
};
|
||||
}
|
||||
|
||||
UnaryExpression(node) {
|
||||
return context => {
|
||||
return !node.argument(context);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
|
@ -43,6 +43,16 @@ describe('conditions', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('does not contain', () => {
|
||||
it('fails when operand contains substring', () => {
|
||||
expect(test('if @issue.title does not contain "bug"')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('passes when operand does not contain substring', () => {
|
||||
expect(test('if @issue.title does not contain "nope"')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('matches', () => {
|
||||
it('passes when operand matches regexp', () => {
|
||||
expect(test('if @sender.login matches "ke+"')).toBeTruthy();
|
||||
|
@ -53,6 +63,16 @@ describe('conditions', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('does not match', () => {
|
||||
it('fails when operand matches regexp', () => {
|
||||
expect(test('if @sender.login does not match "ke+"')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('passes when operand does not match regexp', () => {
|
||||
expect(test('if @issue.title does not match "nope"')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('or', () => {
|
||||
it('passes if either operand is truthy', () => {
|
||||
expect(test('if labeled(bug) or labeled(feature)')).toBeTruthy();
|
||||
|
@ -72,4 +92,14 @@ describe('conditions', () => {
|
|||
expect(test('if labeled(bug) and labeled(nope)')).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('not', () => {
|
||||
it('passes if condition is not truthy', () => {
|
||||
expect(test('if not labeled(something)')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('fails if condition is truthy', () => {
|
||||
expect(test('if not labeled(bug)')).toBeFalsy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -16,3 +16,14 @@ then comment("No bots allowed!") and close;
|
|||
on issues.opened if @sender.login is "bkeepers" then close;
|
||||
on issues.opened if @sender.login is not "bkeepers" then close;
|
||||
on issues.opened if @issue.body contains "- [ ]" then label(wip);
|
||||
|
||||
on issues.opened
|
||||
if not labeled(bug)
|
||||
then close;
|
||||
|
||||
on issues.opened
|
||||
if @issue.body does not match "### Prerequisites.*### Description.*### Steps to Reproduce.*### Versions"
|
||||
or @issue.body.body contains "- [ ]"
|
||||
then
|
||||
label("insufficient-info")
|
||||
and close;
|
||||
|
|
|
@ -127,6 +127,16 @@ describe('parser', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('not', () => {
|
||||
it('negates conditions', () => {
|
||||
expect(parse('if not labeled(bug)')).toEqual({
|
||||
type: 'UnaryExpression',
|
||||
operator: 'not',
|
||||
argument: {type: 'condition', name: 'labeled', value: 'bug'}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('precedence', () => {
|
||||
it('orders "and" over "or"', () => {
|
||||
expect(parse('if true and false or true')).toEqual({
|
||||
|
|
Loading…
Reference in New Issue