travis-conditions 0.0.2 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
  ```