diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 81b6095712..dbf2eeb5ad 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -29,6 +29,17 @@ jobs: fail-fast: false matrix: python-version: ["3.8", "3.9", "3.10"] + # A/B TESTING: add AB_ as needed. Alternatively you may use 'include' + # statements. + # For each A/B runtime version there must be two files: + # - AB_environment/AB_.conda.yaml + # - AB_environment/AB_.dask.yaml + # Search for "A/B TESTING" for further change points in this file + runtime-version: [latest] + # TODO comment out before merge + include: + - python-version: "3.9" + runtime-version: AB_sample steps: - uses: actions/checkout@v2 @@ -75,7 +86,7 @@ jobs: export PYTHON_VERSION_FORMATTED=$(echo "${{ matrix.python-version }}" | sed 's/\.//g' ) export REF_NAME_FORMATTED=$(echo "$GITHUB_REF_NAME" | sed 's/\./-/g' ) export COILED_SOFTWARE_NAME_HEAD=dask-engineering/coiled-runtime-${{ github.event_name }} - export COILED_SOFTWARE_NAME_TAIL=$GITHUB_RUN_ID-py$PYTHON_VERSION_FORMATTED + export COILED_SOFTWARE_NAME_TAIL=$GITHUB_RUN_ID-${{ matrix.runtime-version }}-py$PYTHON_VERSION_FORMATTED if [[ ${{ github.event_name }} = 'pull_request' ]] then @@ -84,14 +95,23 @@ jobs: export COILED_SOFTWARE_NAME=$COILED_SOFTWARE_NAME_HEAD-$GITHUB_REF_TYPE-$REF_NAME_FORMATTED-$COILED_SOFTWARE_NAME_TAIL fi - # Create conda environment.yaml file for the latest software environment - python ci/create_latest_runtime_meta.py - export ENV_FILE=latest.yaml + if [[ ${{ matrix.runtime-version }} = 'latest' ]] + then + # Create conda environment.yaml file for the latest software environment + python ci/create_latest_runtime_meta.py + export COILED_SOFTWARE_ENV="" + else + cp AB_environments/${{ matrix.runtime-version }}.conda.yaml coiled_software_environment.yaml + export COILED_SOFTWARE_ENV=$(python ci/dask_config_to_env.py AB_environments/${{ matrix.runtime-version }}.dask.yaml) + fi + + export ENV_FILE=coiled_software_environment.yaml cat $ENV_FILE mamba install coiled echo "Creating Coiled software environment for $COILED_SOFTWARE_NAME" - coiled env create --name $COILED_SOFTWARE_NAME --conda $ENV_FILE + echo "Environment parameters: $COILED_SOFTWARE_ENV" + coiled env create --name $COILED_SOFTWARE_NAME --conda $ENV_FILE $COILED_SOFTWARE_ENV # Put COILED_SOFTWARE_NAME into a file so it can be downloaded in subsequent workflow jobs echo $COILED_SOFTWARE_NAME > software_name.txt @@ -99,9 +119,9 @@ jobs: - name: Upload environment file uses: actions/upload-artifact@v3 with: - name: software-environment-py${{ matrix.python-version }} + name: software-environment-${{ matrix.runtime-version }}-py${{ matrix.python-version }} path: | - latest.yaml + coiled_software_environment.yaml software_name.txt test_upstream.txt @@ -113,9 +133,14 @@ jobs: strategy: fail-fast: false matrix: - os: ["ubuntu-latest"] + os: [ubuntu-latest] python-version: ["3.9"] - runtime-version: ["latest", "0.0.4", "0.1.0"] + # A/B TESTING: add AB_ as needed (as specified in 'software') + # and remove what is not interesting for the test. + # You may also want to use include/exclude statements for specific + # combinations of python versions and OSs. + # runtime-version: [latest, "0.0.4", "0.1.0", AB_sample] + runtime-version: [latest, "0.0.4", "0.1.0", AB_sample] # TODO revert before merging steps: - uses: actions/checkout@v2 @@ -132,10 +157,10 @@ jobs: environment-file: ci/environment.yml - name: Download software environment assets - if: matrix.runtime-version == 'latest' + if: matrix.runtime-version == 'latest' || startsWith(matrix.runtime-version, 'AB_') uses: actions/download-artifact@v3 with: - name: software-environment-py${{ matrix.python-version }} + name: software-environment-${{ matrix.runtime-version }}-py${{ matrix.python-version }} - name: Install coiled-runtime env: @@ -168,9 +193,14 @@ jobs: strategy: fail-fast: false matrix: - os: ["ubuntu-latest"] + os: [ubuntu-latest] python-version: ["3.9"] - runtime-version: ["latest", "0.0.4", "0.1.0"] + # A/B TESTING: add AB_ as needed (as specified in 'software') + # and remove what is not interesting for the test. + # Alternatively you may use include/exclude statements for specific + # combinations of python versions and OSs. + # runtime-version: [latest, "0.0.4", "0.1.0", AB_sample] + runtime-version: [latest, "0.0.4", "0.1.0", AB_sample] # TODO revert before merging steps: - uses: actions/checkout@v2 @@ -187,10 +217,10 @@ jobs: environment-file: ci/environment.yml - name: Download software environment assets - if: matrix.runtime-version == 'latest' + if: matrix.runtime-version == 'latest' || startsWith(matrix.runtime-version, 'AB_') uses: actions/download-artifact@v3 with: - name: software-environment-py${{ matrix.python-version }} + name: software-environment-${{ matrix.runtime-version }}-py${{ matrix.python-version }} - name: Install coiled-runtime env: @@ -223,16 +253,23 @@ jobs: strategy: fail-fast: false matrix: - os: ["ubuntu-latest"] + os: [ubuntu-latest] python-version: ["3.8", "3.9", "3.10"] - runtime-version: ["latest", "0.0.4", "0.1.0"] + # A/B TESTING: add AB_ as needed (as specified in 'software') + # and remove what is not interesting for the test. + # Alternatively you may use include/exclude statements for specific + # combinations of python versions and OSs. + runtime-version: [latest, "0.0.4", "0.1.0"] include: - python-version: "3.9" - runtime-version: "latest" - os: "windows-latest" + runtime-version: latest + os: windows-latest - python-version: "3.9" - runtime-version: "latest" - os: "macos-latest" + runtime-version: latest + os: macos-latest + # TODO comment out before merging + - python-version: "3.9" + runtime-version: AB_sample steps: - uses: actions/checkout@v2 @@ -249,10 +286,10 @@ jobs: environment-file: ci/environment.yml - name: Download software environment assets - if: matrix.runtime-version == 'latest' + if: matrix.runtime-version == 'latest' || startsWith(matrix.runtime-version, 'AB_') uses: actions/download-artifact@v3 with: - name: software-environment-py${{ matrix.python-version }} + name: software-environment-${{ matrix.runtime-version }}-py${{ matrix.python-version }} - name: Install coiled-runtime env: diff --git a/.gitignore b/.gitignore index c3d511b0c9..272b49eb25 100644 --- a/.gitignore +++ b/.gitignore @@ -120,6 +120,9 @@ venv.bak/ # Rope project settings .ropeproject +# PyCharm project settings +.idea + # mkdocs documentation /site diff --git a/AB_environments/AB_sample.conda.yaml b/AB_environments/AB_sample.conda.yaml new file mode 100644 index 0000000000..701adb51ff --- /dev/null +++ b/AB_environments/AB_sample.conda.yaml @@ -0,0 +1,16 @@ +# Sample conda environment file for A/B testing +# It *must* be called AB_.conda.yaml +# and *must* be accompanied by AB_.dask.yaml +channels: + - conda-forge +dependencies: + - python=3.9 + # Alternatively, we could use a nightly build, or no coiled-runtime at all + - coiled-runtime=0.1.0 + - pip: + # Notes: + # - You can't install anything with conda which conflicts the versions + # pinned in coiled-runtime. Pip packages ignore these restrictions. + # - You can point to your own git fork instead + - dask==2022.8.1 + - git+https://github.com/dask/distributed@dd81b424971e81616e1a52fa09ce4698a5002d41 diff --git a/AB_environments/AB_sample.dask.yaml b/AB_environments/AB_sample.dask.yaml new file mode 100644 index 0000000000..00c47f63ca --- /dev/null +++ b/AB_environments/AB_sample.dask.yaml @@ -0,0 +1,7 @@ +# Sample dask config file for A/B testing +# It *must* be called AB_.dask.yaml +# and *must* be accompanied by AB_.conda.yaml +# Leave empty if you don't want to override anything. +distributed: + scheduler: + worker-saturation: 1.2 diff --git a/ci/create_latest_runtime_meta.py b/ci/create_latest_runtime_meta.py index 16d1a8d3aa..4a7fa2680e 100644 --- a/ci/create_latest_runtime_meta.py +++ b/ci/create_latest_runtime_meta.py @@ -53,7 +53,7 @@ def main(): "channels": ["conda-forge"], "dependencies": requirements, } - with open("latest.yaml", "w") as f: + with open("coiled_software_environment.yaml", "w") as f: yaml.dump(env, f) diff --git a/ci/scripts/dask_config_to_env.py b/ci/scripts/dask_config_to_env.py new file mode 100755 index 0000000000..6e18b59b9b --- /dev/null +++ b/ci/scripts/dask_config_to_env.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python +"""Read a dask config file and print it out in the format `-e ENV=VALUE ENV=VALUE ...` +This script is a work-around to not being able to upload dask config files to +`conda env create`. +""" +from __future__ import annotations + +import sys +from typing import Iterator + +import yaml + + +def main(fname: str) -> None: + with open(fname) as fh: + cfg = yaml.safe_load(fh) + # Print nothing in case of empty file, comments only, or empty dict + if cfg: + print("-e " + " ".join(traverse(cfg, []))) + + +def traverse(node: dict | list | str | float | None, path: list[str]) -> Iterator[str]: + if isinstance(node, dict): + for k, v in node.items(): + k = k.upper().replace("-", "_") + yield from traverse(v, path + [k]) + return + + if not path: + raise ValueError("The top-level element must be a dict") + if isinstance(node, str) and "'" in node: + raise ValueError("Unsupported character: ' (single quote)") + + yield "'DASK_" + "__".join(path) + f"={node}'" + + +if __name__ == "__main__": + main(sys.argv[1]) diff --git a/ci/scripts/install_coiled_runtime.sh b/ci/scripts/install_coiled_runtime.sh index aa52a4b748..a98a155bb4 100644 --- a/ci/scripts/install_coiled_runtime.sh +++ b/ci/scripts/install_coiled_runtime.sh @@ -5,10 +5,10 @@ set -o errexit set -o nounset set -o xtrace -if [[ "$COILED_RUNTIME_VERSION" = 'latest' ]] +if [[ "$COILED_RUNTIME_VERSION" =~ latest|AB_ ]] then - cat latest.yaml - mamba env update --file latest.yaml + cat coiled_software_environment.yaml + mamba env update --file coiled_software_environment.yaml else mamba install -c conda-forge coiled-runtime=$COILED_RUNTIME_VERSION fi diff --git a/ci/scripts/run_tests.sh b/ci/scripts/run_tests.sh index 85a2dca5b1..eea31ed9ed 100644 --- a/ci/scripts/run_tests.sh +++ b/ci/scripts/run_tests.sh @@ -5,7 +5,7 @@ set -o xtrace BENCHMARK="${BENCHMARK:-false}" # Ensure we run additional tests when testing the latest coiled-runtime -if [[ $COILED_RUNTIME_VERSION = 'latest' ]] +if [[ "$COILED_RUNTIME_VERSION" =~ latest|AB_ ]] then EXTRA_OPTIONS="--run-latest" export COILED_SOFTWARE_NAME=$(cat software_name.txt)