Support for multiple phases, with configurable error behaviour


#1

While trying to write a circleci 2.0 config for my project, i’m running into some limitations in the current steps approach. Here’s a rough sketch of how it looks:

- checkout
- run: ./deps.sh  # Install dependencies
- run: ./lint.sh
- run: ./coverage.sh
- run: ./integration_tests.sh
- run: |  # Gather artifacts
      cp -a coverage /tmp/artifacts
      cp -a logs /tmp/artifacts/
      tar czf /tmp/artifacts.tgz /tmp/artifacts/
- store_artifacts:
    path: /tmp/artifacts.tgz
    destination: artifacts.tgz

If, say, the coverage step fails, the integration steps aren’t run, and no artifacts are gathered.

The immediate problem is that run step failure is fatal, the bigger-picture problem is that there’s no way to group steps into phases. What i would like is something like this:

- steps:  # Setup phase
  - on_error: stop # If any steps in this phase fail, then stop the build immediately
  - run: checkout
  - run: ./deps.sh
- steps: # Test phase
  - on_error: continue # If any steps in this phase fail, continue.
  - run: ./lint.sh
  - run: ./coverage.sh
  - run: ./integration_tests.sh
- steps: # Teardown phase.
  - run: |  # Gather artifacts
        cp -a coverage /tmp/artifacts
        cp -a logs /tmp/artifacts/
        tar czf /tmp/artifacts.tgz /tmp/artifacts/
  - store_artifacts:
      path: /tmp/artifacts.tgz
      destination: artifacts.tgz

This would allow me to properly express the logic i need. The first (setup) phase will always run; if it succeeds the second (test) phase will be run. Even if some steps in the test phase fail, the rest of the phase will be run. And finally the artifacts will be gathered if the setup phase passed, regardless of how many tests failed. I would suggest that the default on_error behaviour would be stop, so it would be consistent with the current status.

The only way to get this behaviour with the current system would be to implement some ugly shell scripting; something like:

- checkout
- run: ./deps.sh
- run: |
  set +e
  ret=0
  ./lint.sh
  ret=$((ret+$?))
  ./coverage.sh
  ret=$((ret+$?))
  ./integration_tests.sh
  ret=$((ret+$?))
  cp -a coverage /tmp/artifacts
  ret=$((ret+$?))
  cp -a logs /tmp/artifacts/
  ret=$((ret+$?))
  tar czf /tmp/artifacts.tgz /tmp/artifacts/
  ret=$((ret+$?))
  return $ret
- store_artifacts:
    path: /tmp/artifacts.tgz
    destination: artifacts.tgz

This loses most of the benefit of being able to separate out actions into different steps, and have them easily represented at the top-level of the circleci interface.


#2

Here’s my thread requesting the same functionality, including a quite similar looking flag on the run steps (I called mine halt_build_on_fail)


#3