cirruslabs / cirrus-ci-docs

Documentation for Cirrus CI 📚
https://cirrus-ci.org
MIT License
351 stars 109 forks source link

Specifying tasks types via environment variable / overriding task types #1215

Open anarazel opened 1 year ago

anarazel commented 1 year ago

Hi,

For an open source process it makes a lot of sense to allow everyone to use cirrus-ci in their forks using the "free" credits, but to use custom compute or persistent runners for the, commonly much higher, usage of the project itself. The switch would need to happen based on what's present in repository level environment variables. Right now that's somewhat painful to implement in .cirrus.yml however.

Part of the issue are some small differences in the way tasks are specified. E.g. for custom_engine_instance: image families are specified via image: family/docker-kvm whereas for gce_instance: they are specified as image_family: ubuntu-2204-lts-arm64.

My current best guess for how to implement this is something roughly like:

linux_instance: &linux_instance
  matrix:
    - only_if: $BUILD_METHOD == 'ours'
      gce_instance:
        image_family: $image_family

    - only_if: $BUILD_METHOD == 'cirrus'
      compute_engine_instance:
        image: family/$image_family

macos_instance: &macos_instance
  matrix:
    - only_if: $BUILD_METHOD == 'ours'
      persistent_worker:
        isolation:
          tart:
            image: $image

    - only_if: $BUILD_METHOD == 'cirrus'
      macos_instance:
        image: $image

task:
  name: some linux task
  env:
    image_family: some-image
  <<: *linux_instance

task:
  name: some macos task
  env:
    image: ghcr.io/cirruslabs/macos-ventura-base:latest
  <<: *macos_instance

Which does end up somewhat painful...

Thanks,

Andres

fkorotkov commented 1 year ago

I think you can already achieve this using Starlark and CIRRUS_REPO_OWNER environment variable. You can extract the YAML achors in two different files like .ci/our_instances.yml and .ci/cirrus_instances.yml and put something like the following in your .cirrus.star file:

load("cirrus", "env", "fs")

def main(ctx):
  if env.get("CIRRUS_REPO_OWNER") == "OUR GITHUB ORGANIZATION":
    return fs.read(".ci/our_instances.yml")

  return fs.read(".ci/cirrus_instances.yml")
anarazel commented 1 year ago

Unfortunately I think that doesn't work, presumably due to yaml anchors having to be defined before they're used, and the starlark configuration is appended to .cirrus.yml. I get Error while parsing tasks: INVALID_ARGUMENT: yaml: unknown anchor 'linux_instance' referenced! and .cirrus.star isn't even executed.

anarazel commented 1 year ago

Nor does my sketch from above work: matrix can be defined only under a task, docker_builder or pipe

fkorotkov commented 1 year ago

You can probably move .cirrus.yml into .ci/cirrus.yml and then do concatication in any order you'd like in .cirrus.start.

load("cirrus", "env", "fs")

def main(ctx):
  if env.get("CIRRUS_REPO_OWNER") == "OUR GITHUB ORGANIZATION":
    return fs.read(".ci/our_instances.yml") + "\n" + fs.read(".ci/cirrus.yml")

  return fs.read(".ci/cirrus_instances.yml") + "\n" + fs.read(".ci/cirrus.yml")