Skip to content

Switch statements #2345

@dakom

Description

@dakom

Description

There is already an open issue for if statements at #608. This can be considered an alternative proposal since it would cover that use-case as well, but it really speaks to a different use-case of branching on multiple variants of a single test. That's a bit wordy, let's look at an example :)

Imagine we have if and we want to run different tasks depending on a DEPLOY_ENV var. We could model it like this:

tasks:
  deploy:
    deps: [deploy-prod, deploy-staging, deploy-dev]

  deploy-prod:
    if:
      - sh: '[ "{{.DEPLOY_ENV}}" = "prod" ]'
    cmds:
      - echo "Deploying to production"
    
  deploy-staging:
    if:
      - sh: '[ "{{.DEPLOY_ENV}}" = "staging" ]'
    cmds:
      - echo "Deploying to staging"

  deploy-dev:
    if:
      - sh: '[ "{{.DEPLOY_ENV}}" = "dev" ]'
    cmds:
      - echo "Deploying to development"

However, there's a few problems:

  1. The overall logic is spread among a bunch of tasks, it's hard to see what's happening as we add more
  2. It's too easy for the subtasks to add their own additional logic, which can drastically impact the ability to reason about what's going on
  3. There's no exhaustiveness checks.

In other words, if works well enough for one or two small "branches", but it gets too unwieldy at scale.

What if instead, we had switch, and it looked like this:

tasks:
  requires:
      vars: [DEPLOY_ENV]
  deploy:
    - switch "{{.DEPLOY_ENV}}"
      - case "prod"
        - cmds:
          - echo "Deploying to prod"
      - case "staging"
        - cmds:
          - echo "Deploying to staging"
      - case "dev"
        - cmds:
          - echo "Deploying to dev"
      - default
        - cmds:
          - echo "Unknown deploy target {{.DEPLOY_ENV}}"

Solves all those problems:

  1. It's all located together
  2. The case matching is done on only the specified switch, no room to introduce hidden logic
  3. Exhaustiveness checks with default

Much cleaner imho!

Complex conditions can be done by assigning some output to a var and switching on that, though if really helpful, this would be cool too:

tasks:
  deploy:
    - switch
      - sh: task some-complex-assignment
      - case "prod" # not sure about indentation here
      ...

But I don't think that's necessary, running the sh assignment to a local var is totally fine

(btw, just for the sake of completeness, this exact problem could be solved by just having subtasks and running task deploy-{{.DEPLOY_ENV}} but it's just an example, real-world problems aren't always so trivial)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions