CCI 2.1 conditional step on list (steps) parameter type

The docs here state

You may use parameters as your conditions. The empty string will resolve as falsey in when conditions.

It seems then what I want to do is not possible, which is only run a branch of steps if the user supplies them:

  test:
    executor: v3_6
    parameters:
      steps:
        type: steps
        default: []
    steps:
      - checkout
      - install_deps
      - when:
          condition: <<parameters.steps>>
          steps:
            - steps: <<parameters.steps>>
      - unless:
          condition: <<parameters.steps>>
          steps:
            - run: pipenv run pytest --junitxml=test-reports/pytest/junit.xml
            - run: bash <(curl --silent https://codecov.io/bash)
      - store_test_results:
          path: test-reports
      - store_artifacts:
          path: test-report

Are conditions on lists possible?

1 Like

@jasonkuhrt do you know about pre- and post-steps?

https://circleci.com/docs/2.0/reusing-config/#using-pre-and-post-steps

They will allow you to run a certain set of steps only when they are provided.

@jasonkuhrt what if you instead did something like:

  test:
    executor: v3_6
    parameters:
      steps:
        type: steps
        default:
          - run: pipenv run pytest --junitxml=test-reports/pytest/junit.xml
          - run: bash <(curl --silent https://codecov.io/bash)
    steps:
      - checkout
      - install_deps
      - steps: << parameters.steps >>
      - store_test_results:
          path: test-reports
      - store_artifacts:
          path: test-report

This way you don’t need a condition on the presence of steps, you just set them to whatever default you need and run them every time. Would that work for you?

@rose yep which seem great but IIUC wouldn’t really do what I need here which is steps in the middle.

@johnswanson did not think about that! Very clever :slight_smile: That would certainly work here and I’m guessing a pattern I’ll return to in the future. Maybe its worth putting a mention of that pattern into the docs near step-conditions?

@johnswanson one issue that unfortunately reduces utility of the pattern for me is that a param default cannot reference other param values. Example use-case:

commands:
  deploy:
    parameters:
      <<: *param_stage
      <<: *param_place
      <<: *param_notify_on_fail_and_opt_in
      pre:
        type: steps
        default: []
      steps:
        type: steps
        default:
          - run: npx serverless deploy --stage <<parameters.stage>> --place <<parameters.place>>
      post:
        type: steps
        default: []
    steps:
      - checkout
      - attach_workspace:
          # support users who have done package as a previous job
          at: ./
      - install_node_deps
      # this step installs aws-cli so we don't need to do it again in this command
      - utils/inferred_assume_role:
          stage: <<parameters.stage>>
          place: <<parameters.place>>
      - steps: <<parameters.pre>>
      - steps: <<parameters.steps>>
      - steps: <<parameters.post>>
      - when:
          condition: << parameters.notify_on_fail >>
          steps:
            - slack/status:
                fail_only: "true"

Well dang, that’s a great point, thank you for raising it!

I think currently the only way to do what you want here is to have a separate boolean parameter that determines whether the steps are run. That’s obviously not great. I’ll raise this with the team as an issue and figure out how we can improve this.

1 Like

Thanks @johnswanson much appreciated :slight_smile:

My take on this would be, allow parameter defaults to reference other local parameters arbitrarily. Statically resolve parameter defaults in the order dictated by the dependency graph implied by these references. Naturally direct or indirect cyclic dependencies would have to be detected and raise an exception.

Fun puzzle to work on :slight_smile:

0.02