After discussion in T450, new exitcode directive is introduced.
It accepts two mutually exclusive keys tap_last and tap_worst
that extract last or worst outcome from TAP.
Details
- Reviewers
kparal mkrizek jskladan - Maniphest Tasks
- T450: implement --make-fatal and return non-zero exit code if task fails
- Commits
- rLTRN6d0d0cfa52a4: exitcode directive
used this task formula
name: tasktest desc: blah blah maintainer: lbrabec actions: - name: print hello world python: file: hw.py callable: run export: tap - name: return exitcode exitcode: tap_last: ${tap}
Diff Detail
- Repository
- rLTRN libtaskotron
- Lint
Automatic diff as part of commit; lint not applicable. - Unit
Automatic diff as part of commit; unit tests not applicable.
Looks good overall, but please add unittests for the ExitcodeDirective.
libtaskotron/runner.py | ||
---|---|---|
134 | Please document why this is necessary instead of isinstance() |
I guess this is just a preliminary review, since there are no unit tests yet. Some quick comments below.
libtaskotron/directives/exitcode_directive.py | ||
---|---|---|
12 | The docs fail to build. | |
14 | maybe "set runtask exit code" instead of "generate exitcode" | |
30 | Let's document the return type as well, and the values (since they are hard-coded). | |
32–36 | This seems to be part of the returns section, while it should be probably in description. | |
38–39 | "exactly one of keys ..." would be probably more precise | |
40 | Current libtaskotron version is 0.3.17. You should make sure it is not the same as the last publicly released version, and if it is, bump it to 0.3.18 (I guess) and adjust the spec file as well. | |
58–59 | Ditto. | |
63 | Would this be a bit more readable? if ['tap_worst' in input_data, 'tap_last' in input_data].count(True) != 1: Or, alternatively, why do you have not and != together? Would this work? if ('tap_worst' in input_data) == ('tap_last' in input_data): | |
64–65 | Ditto. | |
76 | assert 'tap_last' in input_data above this line would add some extra error checking. Just an idea. | |
78 | This is probably not intended here. But a log.debug statement before every return statement in this directive would be nice. | |
libtaskotron/runner.py | ||
39 | Can you please document (using a standard Sphinx syntax, so that it's visible in the generated docs) what this is for (that's rather obvious) and what values this can have? Number, string, boolean,... and what None means? | |
135 | It would be great to add a comment here documenting the intended intention (i.e. failure should not be overridden with later success). | |
136 | Let's add a log.info here, it's an important change. | |
278–279 | I'd add another log.info here, saying that we're exiting with exit status $number because something failed and this beahavior was requested. |
libtaskotron/directives/exitcode_directive.py | ||
---|---|---|
63 |
The truth is, that the code is flawed - it is supposed to behave like XOR, but is not. The XOR-like behaviour is actually this piece of code: if ('tap_worst' in input_data) != ('tap_last' in input_data): Which corresponds to the ...count() example of yours, but IMHO is quite a bit more readable. |
Thanks, can you please add unit tests?
libtaskotron/directives/exitcode_directive.py | ||
---|---|---|
20–22 | Please also mention what happens when the TAP is empty (no results). | |
39 | I'm mildly confused by input data, it looks like a variable input_data, but without the underscore - but the user doesn't know anything about that variable. It's probably better to say * :class:`.TaskotronDirectiveError`: when there's not exactly one of parameters ``tap_last`` or ``tap_last`` present | |
45–58 | I'd probably include even the python directive step so that it's more obvious. What about: Run a check returning multiple results and make ``runtask`` fail if any of the results is failed:: - name: run my check and return TAP python: file: my_check.py callable: run export: tap - name: set runtask exit code according to the worst result in TAP exitcode: tap_worst: ${tap} Run a check that returns multiple results and one "overall" result (at the end) which is computed according check's internal logic. Then make ``runtask`` fail if the overall result failed:: - name: run my check and return TAP python: file: my_check.py callable: run export: tap - name: set runtask exit code according to the last (overall) result in TAP exitcode: tap_last: ${tap} | |
60–61 | Please move this into the description instead of examples, thanks. | |
84 | I'm confused. Shouldn't this be == after all? | |
98 | The idea of the proposed assert was that you try to catch a error that should never occur (defensive programming). So with your latest change, it would look like this: if 'tap_worst' in input_data: # do something elif 'tap_last' in input_data: # do something else: assert False, "This should never occur" This protects you against future changes (renaming one of the arguments and forgetting adjusting the code here). |
You were quicker than me :) Unit tests look good, a few more use cases would be great to have covered, comments below.
libtaskotron/runner.py | ||
---|---|---|
137–139 | Can you please write a short unit test for this as well? That it was saved correctly the first time, and that it can be overridden with worse but not better result. | |
testing/test_exitcode_directive.py | ||
13 | Please also test an empty TAP (no results), and imparseable TAP (that should probably also be documented to throw an error). Otherwise it looks good. |
Thanks, looks good. Sorry for so many concerns.
Before committing, please add that one missing line of documentation.
libtaskotron/directives/exitcode_directive.py | ||
---|---|---|
92 | Please also add this to the main directive documentation. |
The docs fail to build.