travis-conditions 0.0.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +65 -0
  3. data/Gemfile.lock +1 -1
  4. data/NOTES.md +107 -0
  5. data/README.md +261 -13
  6. data/bin/travis-conditions +34 -0
  7. data/lib/travis/conditions.rb +10 -16
  8. data/lib/travis/conditions/v0.rb +30 -0
  9. data/lib/travis/conditions/v0/data.rb +57 -0
  10. data/lib/travis/conditions/v0/eval.rb +70 -0
  11. data/lib/travis/conditions/v0/parser.rb +204 -0
  12. data/lib/travis/conditions/v1.rb +19 -0
  13. data/lib/travis/conditions/v1/boolean.rb +71 -0
  14. data/lib/travis/conditions/v1/data.rb +75 -0
  15. data/lib/travis/conditions/v1/eval.rb +114 -0
  16. data/lib/travis/conditions/v1/helper.rb +30 -0
  17. data/lib/travis/conditions/v1/parser.rb +214 -0
  18. data/lib/travis/conditions/version.rb +1 -1
  19. data/spec/conditions_spec.rb +15 -0
  20. data/spec/v0/conditions_spec.rb +15 -0
  21. data/spec/{data_spec.rb → v0/data_spec.rb} +6 -1
  22. data/spec/{eval_spec.rb → v0/eval_spec.rb} +1 -1
  23. data/spec/v0/fixtures/failures.txt +342 -0
  24. data/spec/v0/fixtures/passes.txt +1685 -0
  25. data/spec/{parser_spec.rb → v0/parser_spec.rb} +1 -1
  26. data/spec/v1/conditions_spec.rb +44 -0
  27. data/spec/v1/data_spec.rb +30 -0
  28. data/spec/v1/eval_spec.rb +349 -0
  29. data/spec/v1/fixtures/failures.txt +336 -0
  30. data/spec/v1/fixtures/passes.txt +1634 -0
  31. data/spec/v1/parser/boolean_spec.rb +215 -0
  32. data/spec/v1/parser/call_spec.rb +68 -0
  33. data/spec/v1/parser/comma_spec.rb +28 -0
  34. data/spec/v1/parser/cont_spec.rb +41 -0
  35. data/spec/v1/parser/eq_spec.rb +16 -0
  36. data/spec/v1/parser/in_list_spec.rb +60 -0
  37. data/spec/v1/parser/is_pred_spec.rb +24 -0
  38. data/spec/v1/parser/list_spec.rb +36 -0
  39. data/spec/v1/parser/operand_spec.rb +16 -0
  40. data/spec/v1/parser/parens_spec.rb +28 -0
  41. data/spec/v1/parser/quoted_spec.rb +24 -0
  42. data/spec/v1/parser/re_spec.rb +16 -0
  43. data/spec/v1/parser/regex_spec.rb +12 -0
  44. data/spec/v1/parser/space_spec.rb +40 -0
  45. data/spec/v1/parser/term_spec.rb +84 -0
  46. data/spec/v1/parser/val_spec.rb +24 -0
  47. data/spec/v1/parser/var_spec.rb +16 -0
  48. data/spec/v1/parser_spec.rb +486 -0
  49. data/spec/v1/user_spec.rb +223 -0
  50. metadata +48 -9
  51. data/lib/travis/conditions/data.rb +0 -45
  52. data/lib/travis/conditions/eval.rb +0 -68
  53. data/lib/travis/conditions/parser.rb +0 -202
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a86f16c9d6f3b178157b4244a5e6647777d9ac00
4
- data.tar.gz: 50b3bf851a1946ad0a0f2dc51e768b5dfc8ea496
3
+ metadata.gz: 511bf5af9e9ff4684b09b23bdfb45c19cf16974b
4
+ data.tar.gz: 18653ac8eb0886b3c797c25fe7af4eba1f13c6b8
5
5
  SHA512:
6
- metadata.gz: c95e11b39596ad69528635ce1d761ac17ccc9104fbffd7fe3a1b2dc43f830e991275c67d65ea09e5584f24f8b0da61c4c9a455709cce16055d07ceaa8437fd9a
7
- data.tar.gz: a74367ce97002a1ec80e5c1de63547ac2d5a21d12e6af07a0910fe3d4bbddc17b8ef0d510bb08749c9ce286ba234217ba732dc29cba22f45bdf220a2101fd8f0
6
+ metadata.gz: ab283b0406a10b95be7d9ab0ef7c7fd052cd6db37944bd592493e4990983534370354e7de29091465c97f59d244e3dd6703fb133e8dae30ed07167a5c4438188
7
+ data.tar.gz: f98a63783c44fc3ddb29772d2e10290c9367fcb1b0bf63c71d31171c16f6156c3df92a92aacaee8ed1639b1d57bf1a5b6d96521683d6c21a76780f0ab5498763
@@ -0,0 +1,65 @@
1
+ # Changelog
2
+
3
+ ## [Unreleased]
4
+
5
+ ## v1.0.0-dev.1
6
+
7
+ Major parser rewrite, removing Parslet
8
+
9
+ ### Added
10
+ - Variables `os`, `dist`, `group`, `sudo`, `language`, `commit_message`
11
+ - Boolean aliases `&&` (alias to `AND`), `||` (alias to `OR`), `!` (alias to `NOT`)
12
+ - Operator aliases `==` (alias to `=`), `~=` (alias to `=~`)
13
+ - Predicates `true`, `false`
14
+ - Line continuation using `\`
15
+ - Negated `IN` and `IS` operators:
16
+ ```
17
+ NOT branch IN (master, dev) # this worked, and continues to work
18
+ branch NOT IN (master, dev) # this did not work, and now does
19
+
20
+ NOT env(foo) IS present # this worked, and continues to work
21
+ env(foo) IS NOT present # this did not work, and now does
22
+ env(foo) IS blank # btw this is the same
23
+ ```
24
+ - Better boolean language parsing of:
25
+ ```
26
+ # evaluate individual terms (no operator)
27
+ true
28
+ false
29
+ env(FOO)
30
+
31
+ # compare values
32
+ 1 = 1
33
+
34
+ # compare function calls
35
+ env(FOO) = env(BAR)
36
+
37
+ # compare function calls to variables
38
+ env(FOO) = type
39
+
40
+ # nested function calls
41
+ env(env(FOO))
42
+
43
+ # function calls in lists
44
+ repo IN (env(ONE), env(OTHER))
45
+
46
+ # parenthesis
47
+ (tag =~ ^v) AND (branch = master)
48
+ ```
49
+
50
+ ### Changed
51
+ - All values continue to be treated as strings, except `true` and `false`
52
+ which are now treated like Ruby's types.
53
+ - Individual terms such as `true` or `env(FOO)` will now evaluate according
54
+ to Ruby's concept of truthiness: everything is true except for `false`
55
+ and absent values.
56
+ - Var names and unquoted strings starting with a dollar char `$` now raise
57
+ a parse error. Bash code is not available. Quoted strings still can start
58
+ with a dollar char.
59
+
60
+ ## v0.2.0
61
+ ### Changed
62
+ - Reraise Parselet::ParseFailed as Travis::Conditions::ParseError
63
+
64
+ ## v0.1.0
65
+ Initial release
@@ -25,4 +25,4 @@ DEPENDENCIES
25
25
  rspec
26
26
 
27
27
  BUNDLED WITH
28
- 1.15.4
28
+ 1.16.1
@@ -0,0 +1,107 @@
1
+ ### New variables:
2
+
3
+ * `os`
4
+ * `dist`
5
+ * `group`
6
+ * `sudo`
7
+ * `language`
8
+ * `commit_message`
9
+
10
+ ### New predicates:
11
+
12
+ * `true`
13
+ * `false`
14
+
15
+ It is now possible to use `fork IS true` instead of `fork = true`. These mean
16
+ the same, and there's no reason to not use `=`, but we have seen a lot of
17
+ people expect these to work.
18
+
19
+ ### New operator aliases:
20
+
21
+ For the same reason we've added the following operator aliases:
22
+
23
+ * `==` (alias to `=`)
24
+ * `~=` (alias to `=~`)
25
+ * `&&` (alias to `AND`)
26
+ * `||` (alias to `OR`)
27
+ * `!` (alias to `NOT`)
28
+
29
+ ### Negated `IN` and `IS` operators:
30
+
31
+ The operators `IN` and `IS` could not be negated the way users expected.
32
+ We allowed the following:
33
+
34
+ ```
35
+ NOT branch IN (master, dev) # worked, and continues to work
36
+ branch NOT IN (master, dev) # did not work, and now does
37
+
38
+ NOT env(foo) IS present # worked, and continues to work
39
+ env(foo) IS NOT present # did not work, and now does
40
+ env(foo) IS blank # (btw this is the same)
41
+ ```
42
+
43
+ ### Line continuation (multiline conditions):
44
+
45
+ We were surprised to see users to expect line continuation using `\` to work,
46
+ as it does, for example, in Ruby or Python. We liked the idea, so we allowed
47
+ this:
48
+
49
+ ```
50
+ if: env(PRIOR_VERSION) IS present AND \
51
+ env(PRIOR_VERSION) != env(RELEASE_VERSION) AND \
52
+ branch = master AND \
53
+ type = push
54
+ ```
55
+
56
+ Using YAML multiline strings:
57
+
58
+ ```
59
+ if: |
60
+ env(PRIOR_VERSION) IS present AND \
61
+ env(PRIOR_VERSION) != env(RELEASE_VERSION) AND \
62
+ branch = master AND \
63
+ type = push
64
+ ```
65
+
66
+ ### Proper boolean language parsing:
67
+
68
+ Previously it was not possible to:
69
+
70
+ * evaluate individual terms (such as `true`)
71
+ * compare, say, a value (string) to another, one environment variable (function call) to another, or compare function calls to variables (such as `type` or `branch`).
72
+ * nest function calls, or include things other than strings in lists.
73
+ * enclose statements in parenthesis the way one would expect in some places (even though not documented).
74
+
75
+ The following statements now parse and evaluate as expected:
76
+
77
+ ```
78
+ # individual terms
79
+ true
80
+ false
81
+
82
+ # compare values
83
+ 1 = 1
84
+ true != false
85
+
86
+ # compare function calls
87
+ env(FOO) = env(BAR)
88
+
89
+ # compare function calls to variables
90
+ env(FOO) = type
91
+
92
+ # nested function calls
93
+ env(env(FOO))
94
+
95
+ # function calls in lists
96
+ repo IN (env(ONE), env(OTHER))
97
+
98
+ # parenthesis
99
+ (tag =~ ^v) AND (branch = master)
100
+ ```
101
+
102
+ ### No bash code, please
103
+
104
+ Variable names and unquoted strings starting with a dollar char `$` now raise a
105
+ parse error. Bash code is not available, and these expressions will never evaluate
106
+ as the user expects, so it is better to raise an error instead. Quoted strings
107
+ still can start with a dollar char.
data/README.md CHANGED
@@ -1,33 +1,233 @@
1
- # Boolean language for conditional builds, stages, jobs (draft)
1
+ # Boolean language for conditional builds, stages, jobs
2
+
3
+ ## Usage
4
+
5
+ ```ruby
6
+ str = 'branch IN (foo, bar) AND env(baz) =~ ^baz- OR tag IS present'
7
+ data = { branch: 'foo', env: { baz: 'baz-1' }, tag: 'v.1.0.0' }
8
+ Travis::Conditions.parse(str, data)
9
+ # => true
10
+ ```
11
+
12
+ ## EBNF
13
+
14
+ See [this file](https://github.com/travis-ci/travis-conditions/blob/master/lib/travis/conditions/v1/parser.rb#L6-L47) for the EBNF.
15
+
16
+ ## CLI
17
+
18
+ With the gem installed you can use the command `travis-conditions` in order to
19
+ test your conditions locally. For example:
20
+
21
+ ```
22
+ $ travis-conditions "branch = foo" --data '{"branch": "foo"}'
23
+ true
24
+
25
+ $ echo '{"branch": "foo"}' | travis-conditions "branch = foo"
26
+ true
27
+ ```
28
+
29
+ The given `data` hash can include known attributes (such as branch, tag, repo)
30
+ and an `env` key that can either hold a hash, or an array of strings:
31
+
32
+ ```
33
+ $ travis-conditions "env(foo) = bar" --data '{"env": {"foo": "bar"}}'
34
+ true
35
+ $ travis-conditions "env(foo) = bar" --data '{"env": ["foo=bar"]}'
36
+ true
37
+ ```
38
+
39
+ ## Conditions
40
+
41
+ Conditions can be used to filter out, and reject builds, stages, and jobs by
42
+ specifying conditions in your build configuration (your `.travis.yml` file).
43
+ See [Conditional Builds, Stages, and Jobs](/user/conditional-builds-stages-jobs)
44
+ for details.
45
+
46
+ ### Examples
47
+
48
+ ```
49
+ # require the branch name to be master (note for PRs this is the base branch name)
50
+ branch = master
51
+
52
+ # require the tag name to match a regular expression (enclose in slashes for
53
+ # more complicated expressions)
54
+ tag =~ ^v1
55
+ tag =~ /^(v1|v2)/
56
+
57
+ # require the event type to be either `push` or `pull_request`
58
+ type IN (push, pull_request)
59
+
60
+ # require the branch name to not be one of several names
61
+ branch NOT IN (master, dev)
62
+
63
+ # require the sender login name to match a given name (use quotes for strings
64
+ # that contain spaces or special characters)
65
+ sender == my_account
66
+ sender != "deploy bot"
67
+
68
+ # exclude forks
69
+ fork == false
70
+
71
+ # match the commit message
72
+ commit_message !~ /no-deploy/
73
+
74
+ # match the os
75
+ os == linux
76
+ ```
77
+
78
+ ### Integration
79
+
80
+ Conditions are being parsed using [this library](https://github.com/travis-ci/travis-conditions)
81
+ by the component that accepts your build request, and generates your build,
82
+ stages, and jobs.
83
+
84
+ The following known attributes are available:
85
+
86
+ * `type` (the current event type, known event types are: `push`, `pull_request`, `api`, `cron`)
87
+ * `repo` (the current repository slug `owner_name/name`)
88
+ * `branch` (the current branch name; for pull requests: the base branch name)
89
+ * `tag` (the current tag name)
90
+ * `commit_message` (the current commit message)
91
+ * `sender` (the event sender's login name)
92
+ * `fork` (`true` or `false` depending if the repository is a fork)
93
+ * `head_repo` (for pull requests: the head repository slug `owner_name/name`)
94
+ * `head_branch` (for pull requests: the head repository branch name)
95
+ * `os` (the operating system)
96
+ * `language` (the build language)
97
+ * `sudo` (sudo access)
98
+ * `dist` (the distribution)
99
+ * `group` (the image group)
100
+
101
+ Also, environment variables from your build configuration (`.travis.yml`) and
102
+ repository settings are available, and can be matched using `env(FOO)`, see
103
+ below.
104
+
105
+ Note that this means conditions do not have access to the build environment,
106
+ and they are *not* evaluted in Bash. Bash variables or subprocesses can *not*
107
+ be evaluated.
108
+
109
+ Variable names and unquoted strings starting with a dollar char `$` raise a
110
+ parse error, causing the build request to be rejected. Quoted strings still can
111
+ start with a dollar char, so if you definitely need a string to start with a
112
+ dollar char you can enclose it in quotes.
113
+
114
+ ### Specification
115
+
116
+ The following expressions are parsed and evaluated as expected:
117
+
118
+ ```
119
+ # individual terms
120
+ true
121
+ false
122
+
123
+ # compare values
124
+ 1 = 1
125
+ true != false
126
+
127
+ # compare function calls
128
+ env(FOO) = env(BAR)
129
+
130
+ # compare function calls to attributes
131
+ env(FOO) = type
132
+
133
+ # nested function calls
134
+ env(env(FOO))
135
+
136
+ # function calls in lists
137
+ repo IN (env(ONE), env(OTHER))
138
+
139
+ # parenthesis
140
+ (tag =~ ^v) AND (branch = master)
141
+ ```
142
+
143
+ All keywords (such as `AND`, `OR`, `NOT`, `IN`, `IS`, attribute and functions names) are case-insensitive.
144
+
145
+ The only functions currently is:
146
+
147
+ ```
148
+ # (the value of the environment variable `FOO`)
149
+ env(FOO)
150
+ ```
151
+
152
+ The function `env` currently supports environment variables that are given in
153
+ your build configuration (e.g. on `env` or `env.global`), and environment
154
+ variables specified in your repository settings. Note that there is no
155
+ function `env.global` or similar. Instead all environment variables are
156
+ available through `env`.
157
+
158
+ #### Values
159
+
160
+ Values are strings that are given without quotes, not containing any whitespace or special characters, or single or double quoted strings:
2
161
 
3
162
  ```
4
- (NOT [term] OR [term]) AND [term]
163
+ "a word"
164
+ 'a word'
165
+ a_word
5
166
  ```
6
167
 
7
- A term can be can be:
168
+ #### Equality and inequality
8
169
 
9
- #### Equality
170
+ This matches a string literally:
10
171
 
11
172
  ```
12
173
  branch = master
174
+ sender != "my bot"
13
175
  env(foo) = bar
176
+ "bar" = env("foo")
14
177
  ```
15
178
 
16
- #### Match
179
+ #### Regular expressions
180
+
181
+ This matches a string using a regular expression:
17
182
 
18
183
  ```
184
+ # for simple expressions, not ending in a closing parenthesis:
19
185
  branch =~ ^master$
20
186
  env(foo) =~ ^bar$
187
+
188
+ # if an expression needs to include whitespace, or end in a parenthesis wrap it with slashes:
189
+ branch =~ /(master|foo)/
21
190
  ```
22
191
 
23
- #### Include
192
+ Usually parenthesis are not required (e.g. the above list of alternatives could also be written as just `master|foo`). If you do need to end a regular expression with a parenthesis, or if it contains whitespace, then the whole expression needs to be wrapped in `/` slashes.
193
+
194
+ #### Lists
195
+
196
+ This matches against a list (array) of values:
24
197
 
25
198
  ```
26
199
  branch IN (master, dev)
27
200
  env(foo) IN (bar, baz)
28
201
  ```
29
202
 
30
- #### Presence
203
+ Note that commas are required to separate values.
204
+
205
+ Values that include whitespace or special characters should be quoted:
206
+
207
+ ```
208
+ env(foo) IN ("bar baz", "buz bum")
209
+ ```
210
+
211
+ The operator `IN` can be negated as follows:
212
+
213
+ ```
214
+ # these are the same
215
+ NOT branch IN (master, dev)
216
+ branch NOT IN (master, dev)
217
+ ```
218
+
219
+ #### Predicates
220
+
221
+ Known predicates are:
222
+
223
+ ```
224
+ present
225
+ blank
226
+ true
227
+ false
228
+ ```
229
+
230
+ This requires a value to be present or missing:
31
231
 
32
232
  ```
33
233
  branch IS present
@@ -36,11 +236,59 @@ env(foo) IS present
36
236
  env(foo) IS blank
37
237
  ```
38
238
 
39
- ## Usage
239
+ The operator `IS` can be negated as follows:
40
240
 
41
- ```ruby
42
- str = 'branch IN (foo, bar) AND env(baz) =~ ^baz- OR tag IS present'
43
- data = { branch: 'foo', env: { baz: 'baz-1' }, tag: 'v.1.0.0' }
44
- Travis::Conditions.apply(str, data)
45
- # => true
241
+ ```
242
+ # these are all the same
243
+ env(foo) IS NOT present
244
+ NOT env(foo) IS present
245
+ env(foo) IS blank
246
+ ```
247
+
248
+ Note that the operator `IS` is intended to work with the well known predicates `present` and `blank`. It is not the same as `=`, and expressions like the following do *not* work:
249
+
250
+ ```
251
+ # this does not work
252
+ branch IS "master"
253
+
254
+ # instead use =
255
+ branch = "master"
256
+ ```
257
+
258
+ However, `IS` can also be used to match against the boolean values `true` and `false` (this has been included after we found many users to expect this to work):
259
+
260
+ ```
261
+ branch IS true
262
+ branch = true # this is the same
263
+ ```
264
+
265
+ #### Aliases
266
+
267
+ The following aliases are in place:
268
+
269
+ * `!` is an alias to `NOT`
270
+ * `&&` is an alias to `AND`
271
+ * `||` is an alias to `OR`
272
+ * `==` is an alias to `=`
273
+ * `~=` is an alias to `=~`
274
+
275
+ #### Line continuation (multiline conditions):
276
+
277
+ We were surprised to see users to expect line continuation using `\` to work, as it does, for example, in Ruby or Python. We liked the idea, so we allowed the following:
278
+
279
+ ```
280
+ if: env(PRIOR_VERSION) IS present AND \
281
+ env(PRIOR_VERSION) != env(RELEASE_VERSION) AND \
282
+ branch = master AND \
283
+ type = push
284
+ ```
285
+
286
+ Using YAML multiline strings:
287
+
288
+ ```
289
+ if: |
290
+ env(PRIOR_VERSION) IS present AND \
291
+ env(PRIOR_VERSION) != env(RELEASE_VERSION) AND \
292
+ branch = master AND \
293
+ type = push
46
294
  ```