Repository: holoviz/colorcet
Pull request #128: Migrate colorcet to using pixi for development
Author: login: Azaya89
Created: 2025-03-10T19:59:25Z | Merged: 2025-03-14T18:15:59Z

This PR migrates the developer workflow to Pixi. This is aligned with what has already been done for holoviews and hvPlot:

- [x] Create `pixi.toml` to use approach adopted by hvPlot
- [x] Ensure the tests / docs / build workflow work as expected
- [x] Create the developer guide page in the docs




Diff:
diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index f47fb6b..60e8203 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -1,5 +1,4 @@
 name: packages
-
 on:
   push:
     tags:
@@ -12,62 +11,132 @@ on:
   schedule:
     - cron: '0 9 * * SUN'
 
+env:
+  PYTHON_VERSION: "3.11"
+  PACKAGE: "colorcet"
+
+defaults:
+  run:
+    shell: bash -e {0}
+
 jobs:
+  waiting_room:
+    name: Waiting Room
+    runs-on: ubuntu-latest
+    needs: [conda_build, pip_install]
+    if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
+    environment:
+      name: publish
+    steps:
+      - run: echo "All builds have finished, have been approved, and ready to publish"
+
+  pixi_lock:
+    name: Pixi lock
+    runs-on: ubuntu-latest
+    steps:
+      - uses: holoviz-dev/holoviz_tasks/pixi_lock@v0
+
   conda_build:
-    name: Build Conda Packages
-    runs-on: 'ubuntu-latest'
+    name: Build Conda
+    needs: [pixi_lock]
+    runs-on: "ubuntu-latest"
+    steps:
+      - uses: holoviz-dev/holoviz_tasks/pixi_install@v0
+        with:
+          environments: "build"
+          download-data: false
+          install: false
+      - name: conda build
+        run: pixi run -e build build-conda
+      - uses: actions/upload-artifact@v4
+        if: always()
+        with:
+          name: conda
+          path: dist/*.tar.bz2
+          if-no-files-found: error
+
+  conda-publish:
+    name: Publish Conda
+    runs-on: ubuntu-latest
+    needs: [conda_build, waiting_room]
+    if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
     defaults:
       run:
-        shell: bash -l {0}
+        shell: bash -el {0}
     steps:
-      - uses: actions/checkout@v4
-      - name: Fetch unshallow
-        run: git fetch --prune --tags --unshallow -f
-      - uses: conda-incubator/setup-miniconda@v2
+      - uses: actions/download-artifact@v4
+        with:
+          name: conda
+          path: dist/
+      - name: Set environment variables
+        run: |
+          echo "TAG=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
+          echo "CONDA_FILE=$(ls dist/*.tar.bz2)" >> $GITHUB_ENV
+      - uses: conda-incubator/setup-miniconda@v3
         with:
           miniconda-version: "latest"
-          python-version: "3.11"
-          auto-update-conda: true
-      - name: Set output
-        id: vars
-        run: echo "tag=${GITHUB_REF#refs/*/}" >> $GITHUB_OUTPUT
+          channels: "conda-forge"
       - name: conda setup
         run: |
-          conda install anaconda-client conda-build setuptools_scm
-      - name: conda build
-        run: |
-          VERSION=`python -m setuptools_scm` conda build conda.recipe/
+          conda install -y anaconda-client
       - name: conda dev upload
-        if: (github.event_name == 'push' && (contains(steps.vars.outputs.tag, 'a') || contains(steps.vars.outputs.tag, 'b') || contains(steps.vars.outputs.tag, 'rc')))
+        if: contains(env.TAG, 'a') || contains(env.TAG, 'b') || contains(env.TAG, 'rc')
         run: |
-          anaconda --token ${{ secrets.CONDA_UPLOAD_TOKEN }} upload --user pyviz --label=dev $(VERSION=`python -m setuptools_scm` conda build --output conda.recipe)
+          anaconda --token ${{ secrets.CONDA_UPLOAD_TOKEN }} upload --user pyviz --label=dev $CONDA_FILE
       - name: conda main upload
-        if: (github.event_name == 'push' && !(contains(steps.vars.outputs.tag, 'a') || contains(steps.vars.outputs.tag, 'b') || contains(steps.vars.outputs.tag, 'rc')))
+        if: (!(contains(env.TAG, 'a') || contains(env.TAG, 'b') || contains(env.TAG, 'rc')))
         run: |
-          anaconda --token ${{ secrets.CONDA_UPLOAD_TOKEN }} upload --user pyviz --label=dev --label=main $(VERSION=`python -m setuptools_scm` conda build --output conda.recipe)
+          anaconda --token ${{ secrets.CONDA_UPLOAD_TOKEN }} upload --user pyviz --label=dev --label=main $CONDA_FILE
+
   pip_build:
-    name: Build PyPI Packages
-    runs-on: 'ubuntu-latest'
-    defaults:
-      run:
-        shell: bash -l {0}
+    name: Build PyPI
+    needs: [pixi_lock]
+    runs-on: "ubuntu-latest"
     steps:
-      - uses: actions/checkout@v4
-      - name: Fetch unshallow
-        run: git fetch --prune --tags --unshallow -f
-      - name: Set up Python
-        uses: actions/setup-python@v5
+      - uses: holoviz-dev/holoviz_tasks/pixi_install@v0
         with:
-          python-version: "3.11"
-      - name: env setup
-        run: |
-          python -m pip install --upgrade pip
-          python -m pip install build
-      - name: pip build
-        run: |
-          python -m build
-      - name: Publish package to PyPI
-        if: github.event_name == 'push'
+          environments: "build"
+          download-data: false
+          install: false
+      - name: Build package
+        run: pixi run -e build build-pip
+      - uses: actions/upload-artifact@v4
+        if: always()
+        with:
+          name: pip
+          path: dist/
+          if-no-files-found: error
+
+  pip_install:
+    name: Install PyPI
+    runs-on: "ubuntu-latest"
+    needs: [pip_build]
+    steps:
+      - uses: actions/setup-python@v5
+        with:
+          python-version: ${{ env.PYTHON_VERSION }}
+      - uses: actions/download-artifact@v4
+        with:
+          name: pip
+          path: dist/
+      - name: Install package
+        run: python -m pip install dist/*.whl
+      - name: Import package
+        run: python -c "import $PACKAGE; print($PACKAGE._version.__version__)"
+
+  pip_publish:
+    name: Publish to PyPI
+    runs-on: ubuntu-latest
+    needs: [pip_build, waiting_room]
+    if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
+    permissions:
+      id-token: write
+    steps:
+      - uses: pypa/gh-action-pypi-publish@release/v1
+        with:
+          name: pip
+          path: dist/
+      - name: Publish to PyPi
         uses: pypa/gh-action-pypi-publish@release/v1
         with:
           user: ${{ secrets.PPU }}
diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml
index 77d5ec8..262aa44 100644
--- a/.github/workflows/docs.yaml
+++ b/.github/workflows/docs.yaml
@@ -1,6 +1,4 @@
-
 name: docs
-
 on:
   push:
     tags:
@@ -11,7 +9,7 @@ on:
   workflow_dispatch:
     inputs:
       target:
-        description: 'Site to build and deploy'
+        description: 'Site to build and deploy, or dry-run'
         type: choice
         options:
         - dev
@@ -22,38 +20,69 @@ on:
   schedule:
     - cron: '0 9 * * SUN'
 
+defaults:
+  run:
+    shell: bash -e {0}
+
+env:
+  PYTHON_VERSION: "3.11"
+  MPLBACKEND: "Agg"
+
 jobs:
-  build_docs:
-    name: Documentation
+  pixi_lock:
+    name: Pixi lock
+    runs-on: ubuntu-latest
+    steps:
+      - uses: holoviz-dev/holoviz_tasks/pixi_lock@v0
+
+  docs_build:
+    name: Build Documentation
+    needs: [pixi_lock]
     runs-on: 'ubuntu-latest'
     timeout-minutes: 120
-    defaults:
-      run:
-        shell: bash -l {0}
+    outputs:
+      tag: ${{ steps.vars.outputs.tag }}
     env:
-      MPLBACKEND: "Agg"
       DISPLAY: ":99.0"
+      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
     steps:
-      - uses: actions/checkout@v4
+      - uses: holoviz-dev/holoviz_tasks/pixi_install@v0
+        with:
+          environments: docs
+      - name: Build documentation
+        run: pixi run -e docs docs-build
+      - uses: actions/upload-artifact@v4
+        if: always()
         with:
-          fetch-depth: "100"
-      - name: Fetch
-        run: git fetch --prune --tags -f
+          name: docs
+          if-no-files-found: error
+          path: builtdocs
       - name: Set output
         id: vars
-        run: echo "tag=${GITHUB_REF#refs/*/}" >> $GITHUB_OUTPUT
-      - name: Set up Python
-        uses: actions/setup-python@v5
-        with:
-          python-version: '3.11'
-      - name: install
-        run: pip install ."[doc, examples]"
-      - name: build docs
-        run: sphinx-build -b html doc builtdocs
-      - name: git status
         run: |
-          git status
-          git diff
+          echo "Deploying from ref ${GITHUB_REF#refs/*/}"
+          echo "tag=${GITHUB_REF#refs/*/}" >> $GITHUB_OUTPUT
+      - name: report failure
+        if: failure()
+        run: cat /tmp/sphinx-*.log | tail -n 100
+
+  docs_publish:
+    name: Publish Documentation
+    runs-on: "ubuntu-latest"
+    needs: [docs_build]
+    env:
+      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+      AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
+      AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
+      AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }}
+    steps:
+      - uses: actions/download-artifact@v4
+        with:
+          name: docs
+          path: builtdocs/
+      - name: Set output
+        id: vars
+        run: echo "tag=${{ needs.docs_build.outputs.tag }}" >> $GITHUB_OUTPUT
       - name: Deploy dev
         uses: peaceiris/actions-gh-pages@v3
         if: |
diff --git a/.github/workflows/nightly_lock.yaml b/.github/workflows/nightly_lock.yaml
new file mode 100644
index 0000000..c73c106
--- /dev/null
+++ b/.github/workflows/nightly_lock.yaml
@@ -0,0 +1,17 @@
+name: nightly_lock
+on:
+  workflow_dispatch:
+  schedule:
+    - cron: "0 0 * * *"
+
+env:
+  PACKAGE: "colorcet"
+
+jobs:
+  pixi_lock:
+    if: ${{ !github.event.repository.fork }}
+    name: Pixi lock
+    runs-on: ubuntu-latest
+    timeout-minutes: 5
+    steps:
+      - uses: holoviz-dev/holoviz_tasks/pixi_lock@v0
diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml
index 11a1e0e..a545f55 100644
--- a/.github/workflows/test.yaml
+++ b/.github/workflows/test.yaml
@@ -1,5 +1,4 @@
 name: tests
-
 on:
   push:
     branches:
@@ -8,6 +7,19 @@ on:
     branches:
       - "*"
   workflow_dispatch:
+    inputs:
+      target:
+        description: "How much of the test suite to run"
+        type: choice
+        default: default
+        options:
+          - default
+          - full
+      cache:
+        description: "Use cache"
+        type: boolean
+        default: true
+
   schedule:
     - cron: "0 9 * * SUN"
 
@@ -15,51 +27,128 @@ concurrency:
   group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
   cancel-in-progress: true
 
+defaults:
+  run:
+    shell: bash -e {0}
+
+env:
+  DISPLAY: ":99.0"
+  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+  COV: "--cov=./colorcet --cov-report=xml"
+
 jobs:
   pre_commit:
     name: Run pre-commit
     runs-on: "ubuntu-latest"
     steps:
       - uses: holoviz-dev/holoviz_tasks/pre-commit@v0
-  test_suite:
-    name: Pytest on ${{ matrix.python-version }}, ${{ matrix.os }}
-    needs: [pre_commit]
+
+  setup:
+    name: Setup workflow
+    runs-on: ubuntu-latest
+    permissions:
+      pull-requests: read
+    outputs:
+      code_change: ${{ steps.filter.outputs.code }}
+      matrix: ${{ env.MATRIX }}
+    steps:
+      - uses: actions/checkout@v4
+        if: github.event_name != 'pull_request'
+      - name: Check for code changes
+        uses: dorny/paths-filter@v3
+        id: filter
+        with:
+          filters: |
+            code:
+              - 'colorcet/**'
+              - 'pixi.toml'
+              - 'pyproject.toml'
+              - '.github/workflows/test.yaml'
+      - name: Set matrix option
+        run: |
+          if [[ '${{ github.event_name }}' == 'workflow_dispatch' ]]; then
+            OPTION=${{ github.event.inputs.target }}
+          elif [[ '${{ github.event_name }}' == 'schedule' ]]; then
+            OPTION="full"
+          elif [[ '${{ github.event_name }}' == 'push' && '${{ github.ref_type }}' == 'tag' ]]; then
+            OPTION="full"
+          else
+            OPTION="default"
+          fi
+          echo "MATRIX_OPTION=$OPTION" >> $GITHUB_ENV
+      - name: Set test matrix with 'default' option
+        if: env.MATRIX_OPTION == 'default'
+        run: |
+          MATRIX=$(jq -nsc '{
+              "os": ["ubuntu-latest", "macos-latest", "windows-latest"],
+              "environment": ["test-39", "test-312"],
+            }')
+          echo "MATRIX=$MATRIX" >> $GITHUB_ENV
+      - name: Set test matrix with 'full' option
+        if: env.MATRIX_OPTION == 'full'
+        run: |
+          MATRIX=$(jq -nsc '{
+              "os": ["ubuntu-latest", "macos-latest", "windows-latest"],
+              "environment": ["test-38", "test-39", "test-310", "test-311", "test-312"],
+            }')
+          echo "MATRIX=$MATRIX" >> $GITHUB_ENV
+
+  pixi_lock:
+      name: Pixi lock
+      runs-on: ubuntu-latest
+      steps:
+        - uses: holoviz-dev/holoviz_tasks/pixi_lock@v0
+          with:
+            cache: ${{ github.event.inputs.cache == 'true' || github.event.inputs.cache == '' }}
+
+  unit_test_suite:
+    name: unit:${{ matrix.environment }}:${{ matrix.os }}
+    needs: [pre_commit, setup, pixi_lock]
     runs-on: ${{ matrix.os }}
+    if: needs.setup.outputs.code_change == 'true'
     strategy:
       fail-fast: false
-      matrix:
-        os: ["ubuntu-latest", "macos-latest", "windows-latest"]
-        # Run on the full set on schedule, workflow_dispatch and push&tags events, otherwise on a subset.
-        # python-version: ${{ ( github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || ( github.event_name == 'push' && github.ref_type == 'tag' ) ) && fromJSON('["3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]') || fromJSON('["3.7", "3.13"]') }}
-        python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
-        exclude:
-          - os: 'macos-latest'
-            python-version: "3.7"
+      matrix: ${{ fromJson(needs.setup.outputs.matrix) }}
     timeout-minutes: 60
-    defaults:
-      run:
-        shell: bash -e {0}
-    env:
-      MPLBACKEND: "Agg"
-      DISPLAY: ":99.0"
     steps:
-      - uses: actions/checkout@v4
+      - uses: holoviz-dev/holoviz_tasks/pixi_install@v0
         with:
-          fetch-depth: "100"
-      - name: Fetch
-        run: git fetch --prune --tags -f
-      - name: Set up Python ${{ matrix.python-version }}
-        uses: astral-sh/setup-uv@v5
-        with:
-          python-version: ${{ matrix.python-version }}
-          enable-cache: false
-      - name: install
-        run: uv pip install -e ."[tests,tests_examples,tests_extra]"
-      - name: unit tests
-        run: uv run python -m pytest colorcet --cov=colorcet --cov-append --cov-report xml
-      - name: examples tests
-        run: uv run python -m pytest doc --nbval-lax -p no:python
-      - name: doit test_unit_extra
-        run: uv run python -m pytest colorcet --mpl
+          environments: ${{ matrix.environment }}
+      - name: Test Unit
+        run: |
+          pixi run -e ${{ matrix.environment }} test-unit $COV
+      - name: Test Examples
+        run: |
+          pixi run -e ${{ matrix.environment }} test-example
       - uses: codecov/codecov-action@v4
-        if: github.event_name == 'push'
+        with:
+          token: ${{ secrets.CODECOV_TOKEN }}
+
+  core_test_suite:
+    name: core:${{ matrix.environment }}:${{ matrix.os }}
+    needs: [pre_commit, setup, pixi_lock]
+    runs-on: ${{ matrix.os }}
+    if: needs.setup.outputs.code_change == 'true'
+    strategy:
+      fail-fast: false
+      matrix:
+        os: ["ubuntu-latest"]
+        environment: ["test-core"]
+    timeout-minutes: 60
+    steps:
+      - uses: holoviz-dev/holoviz_tasks/pixi_install@v0
+        with:
+          environments: ${{ matrix.environment }}
+      - name: Test Unit
+        run: |
+          pixi run -e ${{ matrix.environment }} test-unit
+
+  result_test_suite:
+    name: result:test
+    needs: [unit_test_suite, core_test_suite]
+    if: always()
+    runs-on: ubuntu-latest
+    steps:
+      - name: check for failures
+        if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')
+        run: echo job failed && exit 1
diff --git a/.gitignore b/.gitignore
index 17b386f..4920305 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,3 +38,7 @@ assets/CET_updates.py
 
 # setuptools_scm
 colorcet/_version.py
+
+# pixi
+.pixi
+pixi.lock
diff --git a/doc/developer_guide.md b/doc/developer_guide.md
new file mode 100644
index 0000000..c1a8771
--- /dev/null
+++ b/doc/developer_guide.md
@@ -0,0 +1,236 @@
+# Setting up a development environment
+
+This guide describes how to install and configure the development environment for contributing to the colorcet repository.
+
+If you have any problems with the steps here, please reach out in the `dev` channel on [Discord](https://discord.gg/rb6gPXbdAr) or on [Discourse](https://discourse.holoviz.org/).
+
+## Quick Overview
+
+0. Open an [issue on Github](https://github.com/holoviz/colorcet/issues) if needed
+1. Fork and clone [colorcet's Github repository](https://github.com/holoviz/colorcet)
+2. Install [`pixi`](https://pixi.sh)
+3. Run `pixi run setup-dev` to create your development environment
+4. Make some changes and run:
+  - `pixi run test-unit` if you updated the source code to run the unit tests
+  - `pixi run test-example` if you updated the notebooks to run them
+  - `pixi run docs-build` if you need to build the website locally
+5. Open a Pull Request
+
+## Preliminaries
+
+### Basic understanding of how to contribute to Open Source
+
+If this is your first open-source contribution, please study one
+or more of the below resources.
+
+- [How to Get Started with Contributing to Open Source | Video](https://youtu.be/RGd5cOXpCQw)
+- [Contributing to Open-Source Projects as a New Python Developer | Video](https://youtu.be/jTTf4oLkvaM)
+- [How to Contribute to an Open Source Python Project | Blog post](https://www.educative.io/blog/contribue-open-source-python-project)
+
+### Git
+
+The colorcet source code is stored in a [Git](https://git-scm.com) source control repository. The first step to working on colorcet is to install Git onto your system. There are different ways to do this, depending on whether you use Windows, Mac, or Linux.
+
+To install Git on any platform, refer to the [Installing Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) section of the [Pro Git Book](https://git-scm.com/book/en/v2).
+
+To contribute to colorcet, you will also need [Github account](https://github.com/join) and knowledge of the [_fork and pull request workflow_](https://docs.github.com/en/get-started/quickstart/contributing-to-projects).
+
+### Pixi
+
+Developing all aspects of colorcet requires a wide range of packages in different environments, but for new contributors the `default` environment will be more than enough.
+
+To make this more manageable, Pixi manages the developer experience. To install Pixi, follow [this guide](https://pixi.sh/latest/#installation).
+
+#### Glossary
+
+- *Tasks*: A task is what can be run with `pixi run <task-name>`. Tasks can be anything from installing packages to running tests.
+- *Environments*: An environment is a set of packages installed in a virtual environment. Each environment has a name; you can run tasks in a specific environment with the `-e` flag. For example, `pixi run -e test-core test-unit` will run the `test-unit` task in the `test-core` environment.
+- *Lock-file*: A lock-file is a file that contains all the information about the environments.
+
+For more information, see the [Pixi documentation](https://pixi.sh/latest/).
+
+:::{admonition} Note
+:class: info
+
+The first time you run `pixi`, it will create a `.pixi` directory in the source directory. This directory will contain all the files needed for the virtual environments. The `.pixi` directory can be large, so it is advised not to put the source directory into a cloud-synced directory.
+
+:::
+
+## Installing the Project
+
+### Cloning the Project
+
+The source code for the colorcet project is hosted on [GitHub](https://github.com/holoviz/colorcet). The first thing you need to do is clone the repository.
+
+1. Go to [github.com/holoviz/colorcet](https://github.com/holoviz/colorcet)
+2. [Fork the repository](https://docs.github.com/en/get-started/quickstart/contributing-to-projects#forking-a-repository)
+3. Run in your terminal: `git clone https://github.com/<Your Username Here>/colorcet`
+
+The instructions for cloning above created a `colorcet` directory at your file system location.
+This `colorcet` directory is the _source checkout_ for the remainder of this document, and your current working directory is this directory.
+
+## Start developing
+
+To start developing, run the following command:
+
+```bash
+pixi run setup-dev
+```
+
+This will create an environment called `default` (in `.pixi/envs`), install colorcet in [editable mode](https://pip.pypa.io/en/stable/topics/local-project-installs/#editable-installs), and install `pre-commit`:
+
+
+:::{admonition} Note
+:class: info
+
+The first time you run it, it will create a `pixi.lock` file with information for all available environments.
+This command will take a minute or so to run.
+
+:::
+
+All available tasks can be found by running `pixi task list`, the following sections will give a brief introduction to the most common tasks.
+
+### Syncing Git tags with upstream repository
+
+If you are working from a forked repository of colorcet, you will need to sync the tags with the upstream repository.
+This is needed because the colorcet version number depends on [`git tags`](https://git-scm.com/book/en/v2/Git-Basics-Tagging).
+Syncing the git tags can be done with:
+
+```bash
+pixi run sync-git-tags
+```
+
+## Developer Environment
+
+The `default` environment is meant to provide all the tools needed to develop colorcet.
+
+This environment is created by running `pixi run setup-dev`. Run `pixi shell` to activate it; this is equivalent to `source venv/bin/activate` in a Python virtual environment or `conda activate` in a conda environment.
+
+If you need to run a command directly instead of via `pixi`, activate the environment and run the command (e.g. `pixi shell` and `pytest colorcet/tests/<somefile.py>`).
+
+### VS Code
+
+This environment can also be selected in your IDE. In VS Code, this can be done by running the command `Python: Select Interpreter` and choosing `{'default': Pixi}`.
+
+<p style="text-align: center">
+  <img
+    src="https://assets.holoviews.org/static/dev_guide/001.png"
+    alt="001"
+    style="width: 45%; display: inline-block"
+  />
+  <img
+    src="https://assets.holoviews.org/static/dev_guide/002.png"
+    alt="002"
+    style="width: 45%; display: inline-block"
+  />
+</p>
+
+To confirm you are using this dev environment, check the bottom right corner:
+
+![003](https://assets.holoviews.org/static/dev_guide/003.png)
+
+### Jupyter Lab
+
+You can launch Jupyter lab with the `default` environment with `pixi run lab`. This can be advantageous when you need to edit the documentation or debug an example notebook.
+
+## Linting
+
+Colorcet uses [`pre-commit`](https://pre-commit.com/) to lint and format the source code. `pre-commit` is installed automatically when running `pixi run setup-dev`; it can also be installed with `pixi run lint-install`.
+`pre-commit` runs all the linters when a commit is made locally. Linting can be forced to run for all the files with:
+
+```bash
+pixi run lint
+```
+
+:::{admonition} Note
+:class: info
+
+Alternatively, if you have `pre-commit` installed elsewhere you can run:
+
+```bash
+pre-commit install  # To install
+pre-commit run --all-files  # To run on all files
+```
+
+:::
+
+## Testing
+
+To help keep colorcet maintainable, all Pull Requests (PR) with code changes should typically be accompanied by relevant tests. While exceptions may be made for specific circumstances, the default assumption should be that a Pull Request without tests will not be merged.
+
+There are three types of tasks and five environments related to tests.
+
+### Unit tests
+
+Unit tests are usually small tests executed with [pytest](https://docs.pytest.org). They can be found in `colorcet/tests/`.
+Unit tests can be run with the `test-unit` task:
+
+```bash
+pixi run test-unit
+```
+
+:::{admonition} Advanced usage
+:class: tip
+
+The task is available in the following environments: `test-39`, `test-310`, `test-311`, `test-312`, and `test-core`. Where the first ones have the same environments except for different Python versions, and `test-core` only has a core set of dependencies.
+
+You can run the task in a specific environment with the `-e` flag. For example, to run the `test-unit` task in the `test-39` environment, you can run:
+
+```bash
+pixi run -e test-39 test-unit
+```
+
+:::
+
+:::{admonition} Advanced usage
+:class: tip
+
+Currently, an editable install needs to be run in each environment. So, if you want to install in the `test-core` environment, you can add `--environment` / `-e` to the command:
+
+```bash
+pixi run -e test-core install
+```
+
+:::
+
+### Example tests
+
+colorcet's documentation consists mainly of Jupyter Notebooks. The example tests execute all the notebooks and fail if an error is raised. Example tests are possible thanks to [nbval](https://nbval.readthedocs.io/) and can be found in the `doc/` folder.
+Example tests can be run with the following command:
+
+```bash
+pixi run test-example
+```
+
+## Documentation
+
+The documentation can be built with the command:
+
+```bash
+pixi run docs-build
+```
+
+A development version of colorcet can be found [here](https://holoviz-dev.github.io/colorcet/). You can ask a maintainer if they want to make a dev release for your PR, but there is no guarantee they will say yes.
+
+## Build
+
+colorcet has two build tasks to build a Python (for pypi.org) and a Conda package (for anaconda.org).
+
+```bash
+pixi run build-pip
+pixi run build-conda
+```
+
+## Continuous Integration
+
+Every push to the `main` branch or any PR branch on GitHub automatically triggers a test build with [GitHub Actions](https://github.com/features/actions).
+
+You can see the list of all current and previous builds at [this URL](https://github.com/holoviz/colorcet/actions)
+
+### Etiquette
+
+GitHub Actions provides free build workers for open-source projects. A few considerations will help you be considerate of others needing these limited resources:
+
+- Run the tests locally before opening or pushing to an opened PR.
+
+- Group commits to meaningful chunks of work before pushing to GitHub (i.e., don't push on every commit).
diff --git a/doc/getting_started/index.rst b/doc/getting_started/index.rst
index 86c0c8e..7d3280c 100644
--- a/doc/getting_started/index.rst
+++ b/doc/getting_started/index.rst
@@ -53,24 +53,3 @@ regular colormap.
 If you have any questions, please refer to the `User Guide <../user_guide/index>`_
 and if that doesn't help, feel free to post an issue on GitHub, question on stackoverflow,
 or discuss on Gitter.
-
-Developer Instructions
-----------------------
-
-1. Install Python and pip.
-
-2. Clone the colorcet git repository if you do not already have it::
-
-    git clone git://github.com/pyviz/colorcet.git
-
-3. Set up a new environment with all the required dependencies::
-
-    cd colorcet
-    # <your command to create a new environment>
-    pip install -e .[all]
-
-4. Run the unit tests / run the examples tests / build the docs ::
-
-    pytest colorcet
-    pytest doc --nbval-lax -p no:python
-    sphinx-build -b html doc builtdocs
diff --git a/doc/index.ipynb b/doc/index.ipynb
index b203b65..2a17452 100644
--- a/doc/index.ipynb
+++ b/doc/index.ipynb
@@ -133,6 +133,7 @@
     "Introduction <self>\n",
     "Getting Started <getting_started/index>\n",
     "User Guide <user_guide/index>\n",
+    "Developer Guide <developer_guide>\n",
     "About <about>\n",
     "```"
    ]
diff --git a/pixi.toml b/pixi.toml
new file mode 100644
index 0000000..cf7fde8
--- /dev/null
+++ b/pixi.toml
@@ -0,0 +1,167 @@
+[project]
+name = "colorcet"
+channels = ["pyviz/label/dev", "conda-forge"]
+platforms = ["linux-64", "osx-arm64", "osx-64", "win-64"]
+
+[activation.env]
+MPLBACKEND = "Agg"
+PYTHONIOENCODING = "utf-8"
+
+[environments]
+default = ["py312", "required", "test-core", "test", "example", "test-example", "lint", "dev"]
+
+[environments.test-38]
+features = ["py38", "required", "test-core", "test", "example", "test-example"]
+no-default-feature = true
+
+[environments.test-39]
+features = ["py39", "required", "test-core", "test", "example", "test-example"]
+no-default-feature = true
+
+[environments.test-310]
+features = ["py310", "required", "test-core", "test", "example", "test-example"]
+no-default-feature = true
+
+[environments.test-311]
+features = ["py311", "required", "test-core", "test", "example", "test-example"]
+no-default-feature = true
+
+[environments.test-312]
+features = ["py312", "required", "test-core", "test", "example", "test-example"]
+no-default-feature = true
+
+[environments.test-core]
+features = ["py313", "required", "test-core"]
+no-default-feature = true
+
+[environments.docs]
+features = ["py311", "required", "doc", "example"]
+no-default-feature = true
+
+[environments.build]
+features = ["py311", "required", "build"]
+no-default-feature = true
+
+[environments.lint]
+features = ["lint"]
+no-default-feature = true
+
+[feature.required.dependencies]
+nomkl = "*"
+pip = "*"
+
+[feature.required.tasks]
+install = 'python -m pip install --no-deps --disable-pip-version-check -e .'
+setup-dev = { depends-on = ["install", "lint-install"] }
+sync-git-tags = 'python scripts/sync_git_tags.py colorcet'
+
+[feature.py38.dependencies]
+python = "3.8.*"
+
+[feature.py39.dependencies]
+python = "3.9.*"
+
+[feature.py310.dependencies]
+python = "3.10.*"
+
+[feature.py311.dependencies]
+python = "3.11.*"
+
+[feature.py312.dependencies]
+python = "3.12.*"
+
+[feature.py312.activation.env]
+COVERAGE_CORE = "sysmon"
+
+[feature.py313.dependencies]
+python = "3.13.*"
+
+[feature.py313.activation.env]
+COVERAGE_CORE = "sysmon"
+
+# =================== DEV ===================
+
+[feature.dev.dependencies]
+jupyterlab = "*"
+jupyterlab-myst = "*"
+setuptools_scm = ">=6"
+
+[feature.dev.tasks]
+lab = 'jupyter lab'
+
+# =================== SHARED DEPS ===================
+
+# Dependencies required to run the notebooks
+[feature.example.dependencies]
+bokeh = "*"
+holoviews = "*"
+matplotlib = "*"
+numpy = "*"
+
+# =================== TESTS ===================
+
+[feature.test-core.dependencies]
+# Minimum dependencies required to run the test suite.
+parameterized = "*"
+pytest = "*"
+pytest-cov = "*"
+pytest-mpl = "*"
+
+[feature.test-example.dependencies]
+# Dependencies required to run the examples notebooks.
+nbval = "*"
+pytest-xdist = "*"
+
+[feature.test.dependencies]
+# Minimum dependencies required to run the test suite.
+matplotlib = "*"
+bokeh = "*"
+packaging = "*"
+
+[feature.test-core.tasks]
+test-unit = 'pytest colorcet/tests'
+
+[feature.test-example.tasks]
+test-example = 'pytest -n logical --dist loadscope --nbval-lax -p no:python'
+
+# =================== DOCS ====================
+
+[feature.doc]
+channels = [
+    # To get dev colorcet, not always needed.
+    "pyviz/label/dev",
+    # To get dev nbsite, not always needed.
+    "pyviz/label/tooling_dev",
+    "conda-forge",
+]
+dependencies = { nbsite = ">=0.8.6" }
+
+[feature.doc.activation.env]
+MOZ_HEADLESS = "1"
+DISPLAY = ":99.0"
+
+[feature.doc.tasks]
+docs-build-sphinx = 'sphinx-build -b html doc builtdocs'
+_docs-install = 'python -m pip install --no-deps --disable-pip-version-check -e .'
+# Depends on _docs-install instead of install as install
+# in the default environment
+docs-build = { depends-on = ["_docs-install", "docs-build-sphinx"] }
+
+# ================== BUILD ====================
+
+[feature.build.dependencies]
+python-build = "*"
+conda-build = "*"
+
+[feature.build.tasks]
+build-conda = 'bash scripts/conda/build.sh'
+build-pip = 'python -m build .'
+
+# =================== LINT ====================
+
+[feature.lint.dependencies]
+pre-commit = "*"
+
+[feature.lint.tasks]
+lint = 'pre-commit run --all-files'
+lint-install = 'pre-commit install'
diff --git a/pyproject.toml b/pyproject.toml
index fea71e7..2613ef3 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -83,5 +83,7 @@ include = ["colorcet"]
 write_to = "colorcet/_version.py"
 
 [tool.pytest.ini_options]
-addopts = "-v --pyargs"
-norecursedirs = "doc .git dist build _build .ipynb_checkpoints"
+addopts = ["--strict-config", "--strict-markers", "--color=yes"]
+minversion = "7"
+xfail_strict = true
+log_cli_level = "INFO"
diff --git a/scripts/conda/build.sh b/scripts/conda/build.sh
new file mode 100644
index 0000000..7f3bd22
--- /dev/null
+++ b/scripts/conda/build.sh
@@ -0,0 +1,14 @@
+#!/usr/bin/env bash
+
+set -euxo pipefail
+
+PACKAGE="colorcet"
+
+python -m build --sdist .
+
+VERSION=$(python -c "import $PACKAGE; print($PACKAGE._version.__version__)")
+export VERSION
+
+conda build scripts/conda/recipe --no-anaconda-upload --no-verify -c conda-forge --package-format 1
+
+mv "$CONDA_PREFIX/conda-bld/noarch/$PACKAGE-$VERSION-py_0.tar.bz2" dist
diff --git a/conda.recipe/meta.yaml b/scripts/conda/recipe/meta.yaml
similarity index 87%
rename from conda.recipe/meta.yaml
rename to scripts/conda/recipe/meta.yaml
index 394ade2..452c736 100644
--- a/conda.recipe/meta.yaml
+++ b/scripts/conda/recipe/meta.yaml
@@ -1,4 +1,4 @@
-{% set pyproject = load_file_data('../pyproject.toml', from_recipe_dir=True) %}
+{% set pyproject = load_file_data('../../../pyproject.toml', from_recipe_dir=True) %}
 {% set buildsystem = pyproject['build-system'] %}
 {% set project = pyproject['project'] %}
 
@@ -10,7 +10,7 @@ package:
   version: {{ version }}
 
 source:
-  path: ..
+  url: ../../../dist/{{ name }}-{{ version }}.tar.gz
 
 build:
   noarch: python
diff --git a/scripts/sync_git_tags.py b/scripts/sync_git_tags.py
new file mode 100644
index 0000000..b2f0d29
--- /dev/null
+++ b/scripts/sync_git_tags.py
@@ -0,0 +1,32 @@
+"""
+Script to sync tags from upstream repository to forked repository
+"""
+
+import sys
+from subprocess import run
+
+
+def main(package: str) -> None:
+    origin = run(['git', 'remote', 'get-url', 'origin'], check=True, capture_output=True)
+    upstream = run(['git', 'remote', 'get-url', 'upstream'], check=False, capture_output=True)
+    url = (
+        f'https://github.com/holoviz/{package}.git'
+        if origin.stdout.startswith(b'http')
+        else f'git@github.com:holoviz/{package}.git'
+    )
+
+    if url == origin.stdout.strip().decode():
+        print('Not a forked repository, exiting.')
+        return
+    elif upstream.returncode:
+        print(f'Adding {url!r} as remote upstream')
+        run(['git', 'remote', 'add', 'upstream', url], check=True, capture_output=True)
+
+    print(f'Syncing tags from {package} repository with your forked repository')
+    run(['git', 'fetch', '--tags', 'upstream'], check=True, capture_output=True)
+    run(['git', 'push', '--tags'], check=True, capture_output=True)
+    print(f'Tags synced successfully with {origin.stdout.strip().decode()}')
+
+
+if __name__ == '__main__':
+    main(sys.argv[1])


Reviews:
user: login: hoxbro
body: It's a great first iteration of this migration. I have left some comments for you (and one for me).

I haven't read the developer_guide.md, but if you haven't already, double-check that everything is also valid for colorcet. 
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-11T15:43:35Z
user: login: Azaya89
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T17:36:30Z
user: login: hoxbro
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-11T17:44:40Z
user: login: Azaya89
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T18:34:29Z
user: login: Azaya89
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T18:46:35Z
user: login: hoxbro
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-12T10:05:23Z
user: login: hoxbro
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-13T15:06:48Z
user: login: Azaya89
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T16:24:13Z
user: login: hoxbro
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-13T16:28:02Z
user: login: Azaya89
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T16:29:45Z
user: login: Azaya89
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T16:31:04Z
user: login: Azaya89
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T16:32:38Z
user: login: hoxbro
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-13T16:55:59Z
user: login: hoxbro
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-13T16:58:02Z
user: login: Azaya89
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T17:11:02Z
user: login: hoxbro
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-13T17:15:18Z
user: login: Azaya89
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T17:16:53Z
user: login: Azaya89
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T19:34:33Z
user: login: Azaya89
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T20:19:32Z
user: login: hoxbro
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-14T07:26:05Z
user: login: hoxbro
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-14T11:11:55Z
user: login: hoxbro
body: Looks like we are almost there. 

Can you thoroughly look at the changes and ensure that nothing is missed? 

Also, remember to open an issue about dropping EOL Python versions. 
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-14T11:17:54Z
user: login: Azaya89
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-14T14:45:43Z
user: login: Azaya89
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-14T16:25:22Z

Review comments:
diff_hunk: @@ -12,64 +12,57 @@ on:
   schedule:
     - cron: '0 9 * * SUN'
 
+env:
+  PYTHON_VERSION: "3.11"
+
+defaults:
+  run:
+    shell: bash -e {0}
+
 jobs:
+  pixi_lock:
+    name: Pixi lock
+    runs-on: ubuntu-latest
+    steps:
+      - uses: holoviz-dev/holoviz_tasks/pixi_lock@v0
+
   conda_build:
-    name: Build Conda Packages
-    runs-on: 'ubuntu-latest'
-    defaults:
-      run:
-        shell: bash -l {0}
+    name: Build Conda
+    needs: [pixi_lock]
+    runs-on: "ubuntu-latest"
     steps:
-      - uses: actions/checkout@v4
-      - name: Fetch unshallow
-        run: git fetch --prune --tags --unshallow -f
-      - uses: conda-incubator/setup-miniconda@v2
+      - uses: holoviz-dev/holoviz_tasks/pixi_install@v0
         with:
-          miniconda-version: "latest"
-          python-version: "3.11"
-          auto-update-conda: true
-      - name: Set output
-        id: vars
-        run: echo "tag=${GITHUB_REF#refs/*/}" >> $GITHUB_OUTPUT
-      - name: conda setup
-        run: |
-          conda install anaconda-client conda-build setuptools_scm
+          environments: "build"
+          download-data: false
+          install: false
       - name: conda build
+        run: pixi run -e build build-conda
+      - name: Set environment variables
         run: |
-          VERSION=`python -m setuptools_scm` conda build conda.recipe/
+          echo "TAG=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
+          echo "CONDA_FILE=$(ls dist/*.tar.bz2)" >> $GITHUB_ENV
       - name: conda dev upload
-        if: (github.event_name == 'push' && (contains(steps.vars.outputs.tag, 'a') || contains(steps.vars.outputs.tag, 'b') || contains(steps.vars.outputs.tag, 'rc')))
-        run: |
-          anaconda --token ${{ secrets.CONDA_UPLOAD_TOKEN }} upload --user pyviz --label=dev $(VERSION=`python -m setuptools_scm` conda build --output conda.recipe)
+        if: contains(env.TAG, 'a') || contains(env.TAG, 'b') || contains(env.TAG, 'rc')
+        run: pixi run -e build publish-conda --token ${{ secrets.CONDA_UPLOAD_TOKEN }} upload --user pyviz --label=dev $CONDA_FILE
       - name: conda main upload
-        if: (github.event_name == 'push' && !(contains(steps.vars.outputs.tag, 'a') || contains(steps.vars.outputs.tag, 'b') || contains(steps.vars.outputs.tag, 'rc')))
-        run: |
-          anaconda --token ${{ secrets.CONDA_UPLOAD_TOKEN }} upload --user pyviz --label=dev --label=main $(VERSION=`python -m setuptools_scm` conda build --output conda.recipe)
+        if: (!(contains(env.TAG, 'a') || contains(env.TAG, 'b') || contains(env.TAG, 'rc')))
+        run: pixi run -e build publish-conda --token ${{ secrets.CONDA_UPLOAD_TOKEN }} upload --user pyviz --label=dev --label=main $CONDA_FILE
path: .github/workflows/build.yaml
user: login: hoxbro
body: I would do it like holoviews does. Splitting it up and not having a publish tasks but two publish jobs, with a waiting room.

This is both from a security perspective, if something goes wrong with one of the packages, and also to save the built packages during development. 
created_at: 2025-03-11T13:56:25Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,25 @@
+name: nightly_lock
+on:
+  workflow_dispatch:
+  schedule:
+    - cron: "0 0 * * *"
+
+env:
+  PACKAGE: "colorcet"
+
+jobs:
+  pixi_lock:
+    if: ${{ !github.event.repository.fork }}
+    name: Pixi lock
+    runs-on: ubuntu-latest
+    timeout-minutes: 5
+    steps:
+      - uses: holoviz-dev/holoviz_tasks/pixi_lock@v0
+      - name: Upload lock-file to S3
+        env:
+          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
+          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
+          AWS_DEFAULT_REGION: "eu-west-1"
+        run: |
+          zip $(date +%Y-%m-%d).zip pixi.lock pixi.toml
+          aws s3 cp ./$(date +%Y-%m-%d).zip s3://assets.holoviz.org/lock/$PACKAGE/
path: .github/workflows/nightly_lock.yaml
user: login: hoxbro
body: Reminder to myself to check if colorcet directory exists on AWS
created_at: 2025-03-11T13:57:53Z
author_association: MEMBER
diff_hunk: @@ -1,5 +1,4 @@
 name: tests
path: .github/workflows/test.yaml
user: login: hoxbro
body: This needs a complete rewrite to match other repos. 
created_at: 2025-03-11T13:58:20Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,177 @@
+[project]
+name = "colorcet"
+channels = ["pyviz/label/dev",  "conda-forge"]
+platforms = ["linux-64", "osx-arm64", "osx-64", "win-64"]
+
+[environments]
+default = [
+    "py312",
+    "required",
+    "test-core",
+    "test",
+    "example",
+    "test-example",
+    "lint",
+    "dev",
+]
+
+[environments.test-39]
path: pixi.toml
user: login: hoxbro
body: You can't drop older Python versions on CI in this PR. You should at least mention that you have done so.  
created_at: 2025-03-11T13:59:08Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,177 @@
+[project]
+name = "colorcet"
+channels = ["pyviz/label/dev",  "conda-forge"]
+platforms = ["linux-64", "osx-arm64", "osx-64", "win-64"]
+
+[environments]
+default = [
+    "py312",
+    "required",
+    "test-core",
+    "test",
+    "example",
+    "test-example",
+    "lint",
+    "dev",
+]
+
+[environments.test-39]
+features = ["py39", "required", "test-core", "test", "example", "test-example"]
+no-default-feature = true
+
+[environments.test-310]
+features = ["py310", "required", "test-core", "test", "example", "test-example"]
+no-default-feature = true
+
+[environments.test-311]
+features = ["py311", "required", "test-core", "test", "example", "test-example"]
+no-default-feature = true
+
+[environments.test-312]
+features = ["py312", "required", "test-core", "test", "example", "test-example"]
+no-default-feature = true
+
+[environments.test-core]
+features = ["py313", "required", "test-core"]
+no-default-feature = true
+
+[environments.docs]
+features = ["py311", "required", "doc", "example"]
+no-default-feature = true
+
+[environments.build]
+features = ["py311", "required", "build"]
+no-default-feature = true
+
+[environments.lint]
+features = ["lint"]
+no-default-feature = true
+
+[feature.required.dependencies]
+nomkl = "*"
+pip = "*"
+# Required
+bokeh = ">=3.1"
+holoviews = ">=1.19.0"
+numpy = ">=1.21"
+packaging = "*"
+panel = ">=1.0"
+param = ">=1.12.0,<3.0"
+
+[feature.required.tasks]
+install = 'python -m pip install --no-deps --disable-pip-version-check -e .'
+install-dev = { cmd = "pre-commit install", depends-on = ["install"] }
+setup-dev = { depends-on = ["install", "lint-install"] }
path: pixi.toml
user: login: hoxbro
body: I think this was just merged into one on hvplot. 
created_at: 2025-03-11T13:59:47Z
author_association: MEMBER
diff_hunk: @@ -1,4 +1,4 @@
-{% set pyproject = load_file_data('../pyproject.toml', from_recipe_dir=True) %}
path: scripts/conda/recipe/meta.yaml
user: login: hoxbro
body: Have you checked if this works locally?
created_at: 2025-03-11T14:01:15Z
author_association: MEMBER
diff_hunk: @@ -12,64 +12,57 @@ on:
   schedule:
     - cron: '0 9 * * SUN'
 
+env:
+  PYTHON_VERSION: "3.11"
+
+defaults:
+  run:
+    shell: bash -e {0}
+
 jobs:
+  pixi_lock:
+    name: Pixi lock
+    runs-on: ubuntu-latest
+    steps:
+      - uses: holoviz-dev/holoviz_tasks/pixi_lock@v0
+
   conda_build:
-    name: Build Conda Packages
-    runs-on: 'ubuntu-latest'
-    defaults:
-      run:
-        shell: bash -l {0}
+    name: Build Conda
+    needs: [pixi_lock]
+    runs-on: "ubuntu-latest"
     steps:
-      - uses: actions/checkout@v4
-      - name: Fetch unshallow
-        run: git fetch --prune --tags --unshallow -f
-      - uses: conda-incubator/setup-miniconda@v2
+      - uses: holoviz-dev/holoviz_tasks/pixi_install@v0
         with:
-          miniconda-version: "latest"
-          python-version: "3.11"
-          auto-update-conda: true
-      - name: Set output
-        id: vars
-        run: echo "tag=${GITHUB_REF#refs/*/}" >> $GITHUB_OUTPUT
-      - name: conda setup
-        run: |
-          conda install anaconda-client conda-build setuptools_scm
+          environments: "build"
+          download-data: false
+          install: false
       - name: conda build
+        run: pixi run -e build build-conda
+      - name: Set environment variables
         run: |
-          VERSION=`python -m setuptools_scm` conda build conda.recipe/
+          echo "TAG=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
+          echo "CONDA_FILE=$(ls dist/*.tar.bz2)" >> $GITHUB_ENV
       - name: conda dev upload
-        if: (github.event_name == 'push' && (contains(steps.vars.outputs.tag, 'a') || contains(steps.vars.outputs.tag, 'b') || contains(steps.vars.outputs.tag, 'rc')))
-        run: |
-          anaconda --token ${{ secrets.CONDA_UPLOAD_TOKEN }} upload --user pyviz --label=dev $(VERSION=`python -m setuptools_scm` conda build --output conda.recipe)
+        if: contains(env.TAG, 'a') || contains(env.TAG, 'b') || contains(env.TAG, 'rc')
+        run: pixi run -e build publish-conda --token ${{ secrets.CONDA_UPLOAD_TOKEN }} upload --user pyviz --label=dev $CONDA_FILE
       - name: conda main upload
-        if: (github.event_name == 'push' && !(contains(steps.vars.outputs.tag, 'a') || contains(steps.vars.outputs.tag, 'b') || contains(steps.vars.outputs.tag, 'rc')))
-        run: |
-          anaconda --token ${{ secrets.CONDA_UPLOAD_TOKEN }} upload --user pyviz --label=dev --label=main $(VERSION=`python -m setuptools_scm` conda build --output conda.recipe)
+        if: (!(contains(env.TAG, 'a') || contains(env.TAG, 'b') || contains(env.TAG, 'rc')))
+        run: pixi run -e build publish-conda --token ${{ secrets.CONDA_UPLOAD_TOKEN }} upload --user pyviz --label=dev --label=main $CONDA_FILE
+
   pip_build:
-    name: Build PyPI Packages
-    runs-on: 'ubuntu-latest'
-    defaults:
-      run:
-        shell: bash -l {0}
+    name: Build PyPI
+    needs: [pixi_lock]
+    runs-on: "ubuntu-latest"
+    permissions:
+      id-token: write
     steps:
-      - uses: actions/checkout@v4
-      - name: Fetch unshallow
-        run: git fetch --prune --tags --unshallow -f
-      - name: Set up Python
-        uses: actions/setup-python@v5
+      - uses: holoviz-dev/holoviz_tasks/pixi_install@v0
         with:
-          python-version: "3.11"
-      - name: env setup
-        run: |
-          python -m pip install --upgrade pip
-          python -m pip install build
-      - name: pip build
-        run: |
-          python -m build
-      - name: Publish package to PyPI
+          environments: "build"
+          download-data: false
+          install: false
+      - name: Build package
+        run: pixi run -e build build-pip
+      - name: Publish to PyPI
         if: github.event_name == 'push'
         uses: pypa/gh-action-pypi-publish@release/v1
-        with:
-          user: ${{ secrets.PPU }}
-          password: ${{ secrets.PPP }}
-          packages-dir: dist/
path: .github/workflows/build.yaml
user: login: hoxbro
body: I'm pretty sure these are still needed.
created_at: 2025-03-11T14:37:09Z
author_association: MEMBER
diff_hunk: @@ -22,38 +20,40 @@ on:
   schedule:
     - cron: '0 9 * * SUN'
 
+defaults:
+  run:
+    shell: bash -e {0}
+
+env:
+  PYTHON_VERSION: "3.11"
+
 jobs:
-  build_docs:
-    name: Documentation
+  pixi_lock:
+    name: Pixi lock
+    runs-on: ubuntu-latest
+    steps:
+      - uses: holoviz-dev/holoviz_tasks/pixi_lock@v0
+
+  docs_build:
+    name: Build Documentation
     runs-on: 'ubuntu-latest'
     timeout-minutes: 120
-    defaults:
-      run:
-        shell: bash -l {0}
     env:
-      MPLBACKEND: "Agg"
path: .github/workflows/docs.yaml
user: login: hoxbro
body: This has been lost, add it to global env variables in pixi.toml
created_at: 2025-03-11T15:00:51Z
author_association: MEMBER
diff_hunk: @@ -22,38 +20,40 @@ on:
   schedule:
     - cron: '0 9 * * SUN'
 
+defaults:
+  run:
+    shell: bash -e {0}
+
+env:
+  PYTHON_VERSION: "3.11"
+
 jobs:
-  build_docs:
-    name: Documentation
+  pixi_lock:
+    name: Pixi lock
+    runs-on: ubuntu-latest
+    steps:
+      - uses: holoviz-dev/holoviz_tasks/pixi_lock@v0
+
+  docs_build:
+    name: Build Documentation
     runs-on: 'ubuntu-latest'
     timeout-minutes: 120
-    defaults:
-      run:
-        shell: bash -l {0}
     env:
-      MPLBACKEND: "Agg"
       DISPLAY: ":99.0"
     steps:
-      - uses: actions/checkout@v4
+      - uses: holoviz-dev/holoviz_tasks/pixi_install@v0
         with:
-          fetch-depth: "100"
-      - name: Fetch
-        run: git fetch --prune --tags -f
+          environments: docs
+      - name: Build documentation
+        run: pixi run -e docs docs-build
       - name: Set output
         id: vars
-        run: echo "tag=${GITHUB_REF#refs/*/}" >> $GITHUB_OUTPUT
-      - name: Set up Python
-        uses: actions/setup-python@v5
-        with:
-          python-version: '3.11'
-      - name: install
-        run: pip install ."[doc, examples]"
-      - name: build docs
-        run: sphinx-build -b html doc builtdocs
-      - name: git status
         run: |
-          git status
-          git diff
+          echo "Deploying from ref ${GITHUB_REF#refs/*/}"
+          echo "tag=${GITHUB_REF#refs/*/}" >> $GITHUB_OUTPUT
+      - name: report failure
+        if: failure()
+        run: cat /tmp/sphinx-*.log | tail -n 100
path: .github/workflows/docs.yaml
user: login: hoxbro
body: My opinion is this should also be split into build and publish (like HoloViews), but it's OK that this is not the case for docs. I would love to see the docs saved to an artifact. 
created_at: 2025-03-11T15:41:26Z
author_association: MEMBER
diff_hunk: @@ -12,64 +12,57 @@ on:
   schedule:
     - cron: '0 9 * * SUN'
 
+env:
+  PYTHON_VERSION: "3.11"
+
+defaults:
+  run:
+    shell: bash -e {0}
+
 jobs:
+  pixi_lock:
+    name: Pixi lock
+    runs-on: ubuntu-latest
+    steps:
+      - uses: holoviz-dev/holoviz_tasks/pixi_lock@v0
+
   conda_build:
-    name: Build Conda Packages
-    runs-on: 'ubuntu-latest'
-    defaults:
-      run:
-        shell: bash -l {0}
+    name: Build Conda
+    needs: [pixi_lock]
+    runs-on: "ubuntu-latest"
     steps:
-      - uses: actions/checkout@v4
-      - name: Fetch unshallow
-        run: git fetch --prune --tags --unshallow -f
-      - uses: conda-incubator/setup-miniconda@v2
+      - uses: holoviz-dev/holoviz_tasks/pixi_install@v0
         with:
-          miniconda-version: "latest"
-          python-version: "3.11"
-          auto-update-conda: true
-      - name: Set output
-        id: vars
-        run: echo "tag=${GITHUB_REF#refs/*/}" >> $GITHUB_OUTPUT
-      - name: conda setup
-        run: |
-          conda install anaconda-client conda-build setuptools_scm
+          environments: "build"
+          download-data: false
+          install: false
       - name: conda build
+        run: pixi run -e build build-conda
+      - name: Set environment variables
         run: |
-          VERSION=`python -m setuptools_scm` conda build conda.recipe/
+          echo "TAG=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
+          echo "CONDA_FILE=$(ls dist/*.tar.bz2)" >> $GITHUB_ENV
       - name: conda dev upload
-        if: (github.event_name == 'push' && (contains(steps.vars.outputs.tag, 'a') || contains(steps.vars.outputs.tag, 'b') || contains(steps.vars.outputs.tag, 'rc')))
-        run: |
-          anaconda --token ${{ secrets.CONDA_UPLOAD_TOKEN }} upload --user pyviz --label=dev $(VERSION=`python -m setuptools_scm` conda build --output conda.recipe)
+        if: contains(env.TAG, 'a') || contains(env.TAG, 'b') || contains(env.TAG, 'rc')
+        run: pixi run -e build publish-conda --token ${{ secrets.CONDA_UPLOAD_TOKEN }} upload --user pyviz --label=dev $CONDA_FILE
       - name: conda main upload
-        if: (github.event_name == 'push' && !(contains(steps.vars.outputs.tag, 'a') || contains(steps.vars.outputs.tag, 'b') || contains(steps.vars.outputs.tag, 'rc')))
-        run: |
-          anaconda --token ${{ secrets.CONDA_UPLOAD_TOKEN }} upload --user pyviz --label=dev --label=main $(VERSION=`python -m setuptools_scm` conda build --output conda.recipe)
+        if: (!(contains(env.TAG, 'a') || contains(env.TAG, 'b') || contains(env.TAG, 'rc')))
+        run: pixi run -e build publish-conda --token ${{ secrets.CONDA_UPLOAD_TOKEN }} upload --user pyviz --label=dev --label=main $CONDA_FILE
+
   pip_build:
-    name: Build PyPI Packages
-    runs-on: 'ubuntu-latest'
-    defaults:
-      run:
-        shell: bash -l {0}
+    name: Build PyPI
+    needs: [pixi_lock]
+    runs-on: "ubuntu-latest"
+    permissions:
+      id-token: write
     steps:
-      - uses: actions/checkout@v4
-      - name: Fetch unshallow
-        run: git fetch --prune --tags --unshallow -f
-      - name: Set up Python
-        uses: actions/setup-python@v5
+      - uses: holoviz-dev/holoviz_tasks/pixi_install@v0
         with:
-          python-version: "3.11"
-      - name: env setup
-        run: |
-          python -m pip install --upgrade pip
-          python -m pip install build
-      - name: pip build
-        run: |
-          python -m build
-      - name: Publish package to PyPI
+          environments: "build"
+          download-data: false
+          install: false
+      - name: Build package
+        run: pixi run -e build build-pip
+      - name: Publish to PyPI
         if: github.event_name == 'push'
         uses: pypa/gh-action-pypi-publish@release/v1
-        with:
-          user: ${{ secrets.PPU }}
-          password: ${{ secrets.PPP }}
-          packages-dir: dist/
path: .github/workflows/build.yaml
user: login: Azaya89
body: OK

created_at: 2025-03-11T17:36:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -12,64 +12,57 @@ on:
   schedule:
     - cron: '0 9 * * SUN'
 
+env:
+  PYTHON_VERSION: "3.11"
+
+defaults:
+  run:
+    shell: bash -e {0}
+
 jobs:
+  pixi_lock:
+    name: Pixi lock
+    runs-on: ubuntu-latest
+    steps:
+      - uses: holoviz-dev/holoviz_tasks/pixi_lock@v0
+
   conda_build:
-    name: Build Conda Packages
-    runs-on: 'ubuntu-latest'
-    defaults:
-      run:
-        shell: bash -l {0}
+    name: Build Conda
+    needs: [pixi_lock]
+    runs-on: "ubuntu-latest"
     steps:
-      - uses: actions/checkout@v4
-      - name: Fetch unshallow
-        run: git fetch --prune --tags --unshallow -f
-      - uses: conda-incubator/setup-miniconda@v2
+      - uses: holoviz-dev/holoviz_tasks/pixi_install@v0
         with:
-          miniconda-version: "latest"
-          python-version: "3.11"
-          auto-update-conda: true
-      - name: Set output
-        id: vars
-        run: echo "tag=${GITHUB_REF#refs/*/}" >> $GITHUB_OUTPUT
-      - name: conda setup
-        run: |
-          conda install anaconda-client conda-build setuptools_scm
+          environments: "build"
+          download-data: false
+          install: false
       - name: conda build
+        run: pixi run -e build build-conda
+      - name: Set environment variables
         run: |
-          VERSION=`python -m setuptools_scm` conda build conda.recipe/
+          echo "TAG=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
+          echo "CONDA_FILE=$(ls dist/*.tar.bz2)" >> $GITHUB_ENV
       - name: conda dev upload
-        if: (github.event_name == 'push' && (contains(steps.vars.outputs.tag, 'a') || contains(steps.vars.outputs.tag, 'b') || contains(steps.vars.outputs.tag, 'rc')))
-        run: |
-          anaconda --token ${{ secrets.CONDA_UPLOAD_TOKEN }} upload --user pyviz --label=dev $(VERSION=`python -m setuptools_scm` conda build --output conda.recipe)
+        if: contains(env.TAG, 'a') || contains(env.TAG, 'b') || contains(env.TAG, 'rc')
+        run: pixi run -e build publish-conda --token ${{ secrets.CONDA_UPLOAD_TOKEN }} upload --user pyviz --label=dev $CONDA_FILE
       - name: conda main upload
-        if: (github.event_name == 'push' && !(contains(steps.vars.outputs.tag, 'a') || contains(steps.vars.outputs.tag, 'b') || contains(steps.vars.outputs.tag, 'rc')))
-        run: |
-          anaconda --token ${{ secrets.CONDA_UPLOAD_TOKEN }} upload --user pyviz --label=dev --label=main $(VERSION=`python -m setuptools_scm` conda build --output conda.recipe)
+        if: (!(contains(env.TAG, 'a') || contains(env.TAG, 'b') || contains(env.TAG, 'rc')))
+        run: pixi run -e build publish-conda --token ${{ secrets.CONDA_UPLOAD_TOKEN }} upload --user pyviz --label=dev --label=main $CONDA_FILE
+
   pip_build:
-    name: Build PyPI Packages
-    runs-on: 'ubuntu-latest'
-    defaults:
-      run:
-        shell: bash -l {0}
+    name: Build PyPI
+    needs: [pixi_lock]
+    runs-on: "ubuntu-latest"
+    permissions:
+      id-token: write
     steps:
-      - uses: actions/checkout@v4
-      - name: Fetch unshallow
-        run: git fetch --prune --tags --unshallow -f
-      - name: Set up Python
-        uses: actions/setup-python@v5
+      - uses: holoviz-dev/holoviz_tasks/pixi_install@v0
         with:
-          python-version: "3.11"
-      - name: env setup
-        run: |
-          python -m pip install --upgrade pip
-          python -m pip install build
-      - name: pip build
-        run: |
-          python -m build
-      - name: Publish package to PyPI
+          environments: "build"
+          download-data: false
+          install: false
+      - name: Build package
+        run: pixi run -e build build-pip
+      - name: Publish to PyPI
         if: github.event_name == 'push'
         uses: pypa/gh-action-pypi-publish@release/v1
-        with:
-          user: ${{ secrets.PPU }}
-          password: ${{ secrets.PPP }}
-          packages-dir: dist/
path: .github/workflows/build.yaml
user: login: hoxbro
body: Updates are needed on the PyPI side of things to remove these. You didn't have a chance to know this!
created_at: 2025-03-11T17:44:40Z
author_association: MEMBER
diff_hunk: @@ -22,38 +20,40 @@ on:
   schedule:
     - cron: '0 9 * * SUN'
 
+defaults:
+  run:
+    shell: bash -e {0}
+
+env:
+  PYTHON_VERSION: "3.11"
+
 jobs:
-  build_docs:
-    name: Documentation
+  pixi_lock:
+    name: Pixi lock
+    runs-on: ubuntu-latest
+    steps:
+      - uses: holoviz-dev/holoviz_tasks/pixi_lock@v0
+
+  docs_build:
+    name: Build Documentation
     runs-on: 'ubuntu-latest'
     timeout-minutes: 120
-    defaults:
-      run:
-        shell: bash -l {0}
     env:
-      MPLBACKEND: "Agg"
path: .github/workflows/docs.yaml
user: login: Azaya89
body: OK
created_at: 2025-03-11T18:34:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,4 +1,4 @@
-{% set pyproject = load_file_data('../pyproject.toml', from_recipe_dir=True) %}
path: scripts/conda/recipe/meta.yaml
user: login: Azaya89
body: Yes it does.
created_at: 2025-03-11T18:46:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,236 @@
+# Setting up a development environment
+
+This guide describes how to install and configure the development environment for contributing to the colorcet repository.
+
+If you have any problems with the steps here, please reach out in the `dev` channel on [Discord](https://discord.gg/rb6gPXbdAr) or on [Discourse](https://discourse.holoviz.org/).
+
+## TL;DR
+
+0. Open an [issue on Github](https://github.com/holoviz/colorcet/issues) if needed
+1. Fork and clone [colorcet's Github repository](https://github.com/holoviz/colorcet)
+2. Install [`pixi`](https://pixi.sh)
+3. Run `pixi run install` to create your development environment
path: doc/developer_guide.md
user: login: hoxbro
body: ```suggestion
3. Run `pixi run setup-dev` to create your development environment
```
created_at: 2025-03-11T21:57:02Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,177 @@
+[project]
+name = "colorcet"
+channels = ["pyviz/label/dev",  "conda-forge"]
+platforms = ["linux-64", "osx-arm64", "osx-64", "win-64"]
+
+[environments]
+default = [
+    "py312",
+    "required",
+    "test-core",
+    "test",
+    "example",
+    "test-example",
+    "lint",
+    "dev",
+]
+
+[environments.test-39]
path: pixi.toml
user: login: hoxbro
body: My point was you can't do this; this PR should only touch the developer-related code; this is a user-related change.  
created_at: 2025-03-11T21:58:24Z
author_association: MEMBER
diff_hunk: @@ -8,58 +7,161 @@ on:
     branches:
       - "*"
   workflow_dispatch:
+    inputs:
+      target:
+        description: "How much of the test suite to run"
+        type: choice
+        default: default
+        options:
+          - default
+          - full
+      cache:
+        description: "Use cache"
+        type: boolean
+        default: true
+
   schedule:
     - cron: "0 9 * * SUN"
 
 concurrency:
   group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
   cancel-in-progress: true
 
+defaults:
+  run:
+    shell: bash -e {0}
+
+env:
+  MPLBACKEND: "Agg"
path: .github/workflows/test.yaml
user: login: hoxbro
body: Remove this is in pixi.toml now
created_at: 2025-03-11T22:01:09Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,25 @@
+name: nightly_lock
+on:
+  workflow_dispatch:
+  schedule:
+    - cron: "0 0 * * *"
+
+env:
+  PACKAGE: "colorcet"
+
+jobs:
+  pixi_lock:
+    if: ${{ !github.event.repository.fork }}
+    name: Pixi lock
+    runs-on: ubuntu-latest
+    timeout-minutes: 5
+    steps:
+      - uses: holoviz-dev/holoviz_tasks/pixi_lock@v0
+      - name: Upload lock-file to S3
+        env:
+          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
+          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
+          AWS_DEFAULT_REGION: "eu-west-1"
+        run: |
+          zip $(date +%Y-%m-%d).zip pixi.lock pixi.toml
+          aws s3 cp ./$(date +%Y-%m-%d).zip s3://assets.holoviz.org/lock/$PACKAGE/
path: .github/workflows/nightly_lock.yaml
user: login: hoxbro
body: Honestly, I don't think we need to upload this to s3; you can remove the upload part. 
created_at: 2025-03-11T22:04:38Z
author_association: MEMBER
diff_hunk: @@ -1,5 +1,4 @@
 name: packages
path: .github/workflows/build.yaml
user: login: hoxbro
body: Can you try running both docs and build workflow from your fork?

![image](https://github.com/user-attachments/assets/7768ac7d-4d27-4733-a741-d9010508da69)

created_at: 2025-03-13T14:29:40Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,24 @@
+name: nightly_lock
+on:
+  workflow_dispatch:
+  schedule:
+    - cron: "0 0 * * *"
+
+env:
+  PACKAGE: "colorcet"
+
+jobs:
+  pixi_lock:
+    if: ${{ !github.event.repository.fork }}
+    name: Pixi lock
+    runs-on: ubuntu-latest
+    timeout-minutes: 5
+    steps:
+      - uses: holoviz-dev/holoviz_tasks/pixi_lock@v0
+      - name: Upload lock-file to S3
+        env:
+          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
+          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
+          AWS_DEFAULT_REGION: "eu-west-1"
+        run: |
+          zip $(date +%Y-%m-%d).zip pixi.lock pixi.toml
path: .github/workflows/nightly_lock.yaml
user: login: hoxbro
body: ```suggestion
```

There is no need to do this if we are not uploading it. 
created_at: 2025-03-13T14:43:49Z
author_association: MEMBER
diff_hunk: @@ -8,58 +7,160 @@ on:
     branches:
       - "*"
   workflow_dispatch:
+    inputs:
+      target:
+        description: "How much of the test suite to run"
+        type: choice
+        default: default
+        options:
+          - default
+          - full
+      cache:
+        description: "Use cache"
+        type: boolean
+        default: true
+
   schedule:
     - cron: "0 9 * * SUN"
 
 concurrency:
   group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
   cancel-in-progress: true
 
+defaults:
+  run:
+    shell: bash -e {0}
+
+env:
+  DISPLAY: ":99.0"
+  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+  COV: "--cov=./colorcet --cov-report=xml"
+
 jobs:
   pre_commit:
     name: Run pre-commit
     runs-on: "ubuntu-latest"
     steps:
       - uses: holoviz-dev/holoviz_tasks/pre-commit@v0
-  test_suite:
-    name: Pytest on ${{ matrix.python-version }}, ${{ matrix.os }}
-    needs: [pre_commit]
+
+  setup:
+    name: Setup workflow
+    runs-on: ubuntu-latest
+    permissions:
+      pull-requests: read
+    outputs:
+      code_change: ${{ steps.filter.outputs.code }}
+      matrix: ${{ env.MATRIX }}
+    steps:
+      - uses: actions/checkout@v4
+        if: github.event_name != 'pull_request'
+      - name: Check for code changes
+        uses: dorny/paths-filter@v3
+        id: filter
+        with:
+          filters: |
+            code:
+              - 'colorcet/**'
+              - 'pixi.toml'
+              - 'pyproject.toml'
+              - '.github/workflows/test.yaml'
+      - name: Set matrix option
+        run: |
+          if [[ '${{ github.event_name }}' == 'workflow_dispatch' ]]; then
+            OPTION=${{ github.event.inputs.target }}
+          elif [[ '${{ github.event_name }}' == 'schedule' ]]; then
+            OPTION="full"
+          elif [[ '${{ github.event_name }}' == 'push' && '${{ github.ref_type }}' == 'tag' ]]; then
+            OPTION="full"
+          else
+            OPTION="default"
+          fi
+          echo "MATRIX_OPTION=$OPTION" >> $GITHUB_ENV
+      - name: Set test matrix with 'default' option
+        if: env.MATRIX_OPTION == 'default'
+        run: |
+          MATRIX=$(jq -nsc '{
+              "os": ["ubuntu-latest", "macos-latest", "windows-latest"],
+              "environment": ["test-39", "test-312"],
+              "exclude": [
+                {
+                "environment": "test-39",
+                "os": "macos-latest"
+                }
+              ]
path: .github/workflows/test.yaml
user: login: hoxbro
body: Is this also needed for colorcet?

And what about testing Python 3.7 and 3.8?
created_at: 2025-03-13T14:47:04Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,237 @@
+# Setting up a development environment
+
+This guide describes how to install and configure the development environment for contributing to the colorcet repository.
+
+If you have any problems with the steps here, please reach out in the `dev` channel on [Discord](https://discord.gg/rb6gPXbdAr) or on [Discourse](https://discourse.holoviz.org/).
+
+## TL;DR
path: doc/developer_guide.md
user: login: hoxbro
body: ```suggestion
## Quick overview
```

I don't like `TL:DR`.

created_at: 2025-03-13T15:03:25Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,237 @@
+# Setting up a development environment
+
+This guide describes how to install and configure the development environment for contributing to the colorcet repository.
+
+If you have any problems with the steps here, please reach out in the `dev` channel on [Discord](https://discord.gg/rb6gPXbdAr) or on [Discourse](https://discourse.holoviz.org/).
+
+## TL;DR
+
+0. Open an [issue on Github](https://github.com/holoviz/colorcet/issues) if needed
+1. Fork and clone [colorcet's Github repository](https://github.com/holoviz/colorcet)
+2. Install [`pixi`](https://pixi.sh)
+3. Run `pixi run setup-dev` to create your development environment
+4. Run `pixi shell` to activate the created environment
path: doc/developer_guide.md
user: login: hoxbro
body: This is not a needed step. 
created_at: 2025-03-13T15:03:49Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,237 @@
+# Setting up a development environment
path: doc/developer_guide.md
user: login: hoxbro
body: Have you checked if this looks good on the webpage?
created_at: 2025-03-13T15:04:35Z
author_association: MEMBER
diff_hunk: @@ -1,5 +1,4 @@
 name: packages
path: .github/workflows/build.yaml
user: login: Azaya89
body: Works fine

![image](https://github.com/user-attachments/assets/d0d4bfd4-e8b7-41da-92f8-0bd9242f2e45)

created_at: 2025-03-13T16:24:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,5 +1,4 @@
 name: packages
path: .github/workflows/build.yaml
user: login: hoxbro
body: What about build?
created_at: 2025-03-13T16:28:02Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,237 @@
+# Setting up a development environment
+
+This guide describes how to install and configure the development environment for contributing to the colorcet repository.
+
+If you have any problems with the steps here, please reach out in the `dev` channel on [Discord](https://discord.gg/rb6gPXbdAr) or on [Discourse](https://discourse.holoviz.org/).
+
+## TL;DR
+
+0. Open an [issue on Github](https://github.com/holoviz/colorcet/issues) if needed
+1. Fork and clone [colorcet's Github repository](https://github.com/holoviz/colorcet)
+2. Install [`pixi`](https://pixi.sh)
+3. Run `pixi run setup-dev` to create your development environment
+4. Run `pixi shell` to activate the created environment
path: doc/developer_guide.md
user: login: Azaya89
body: Step 4? In my experience, `pixi run setup-dev` does not activate the environment after creating it.


created_at: 2025-03-13T16:29:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -8,58 +7,160 @@ on:
     branches:
       - "*"
   workflow_dispatch:
+    inputs:
+      target:
+        description: "How much of the test suite to run"
+        type: choice
+        default: default
+        options:
+          - default
+          - full
+      cache:
+        description: "Use cache"
+        type: boolean
+        default: true
+
   schedule:
     - cron: "0 9 * * SUN"
 
 concurrency:
   group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
   cancel-in-progress: true
 
+defaults:
+  run:
+    shell: bash -e {0}
+
+env:
+  DISPLAY: ":99.0"
+  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+  COV: "--cov=./colorcet --cov-report=xml"
+
 jobs:
   pre_commit:
     name: Run pre-commit
     runs-on: "ubuntu-latest"
     steps:
       - uses: holoviz-dev/holoviz_tasks/pre-commit@v0
-  test_suite:
-    name: Pytest on ${{ matrix.python-version }}, ${{ matrix.os }}
-    needs: [pre_commit]
+
+  setup:
+    name: Setup workflow
+    runs-on: ubuntu-latest
+    permissions:
+      pull-requests: read
+    outputs:
+      code_change: ${{ steps.filter.outputs.code }}
+      matrix: ${{ env.MATRIX }}
+    steps:
+      - uses: actions/checkout@v4
+        if: github.event_name != 'pull_request'
+      - name: Check for code changes
+        uses: dorny/paths-filter@v3
+        id: filter
+        with:
+          filters: |
+            code:
+              - 'colorcet/**'
+              - 'pixi.toml'
+              - 'pyproject.toml'
+              - '.github/workflows/test.yaml'
+      - name: Set matrix option
+        run: |
+          if [[ '${{ github.event_name }}' == 'workflow_dispatch' ]]; then
+            OPTION=${{ github.event.inputs.target }}
+          elif [[ '${{ github.event_name }}' == 'schedule' ]]; then
+            OPTION="full"
+          elif [[ '${{ github.event_name }}' == 'push' && '${{ github.ref_type }}' == 'tag' ]]; then
+            OPTION="full"
+          else
+            OPTION="default"
+          fi
+          echo "MATRIX_OPTION=$OPTION" >> $GITHUB_ENV
+      - name: Set test matrix with 'default' option
+        if: env.MATRIX_OPTION == 'default'
+        run: |
+          MATRIX=$(jq -nsc '{
+              "os": ["ubuntu-latest", "macos-latest", "windows-latest"],
+              "environment": ["test-39", "test-312"],
+              "exclude": [
+                {
+                "environment": "test-39",
+                "os": "macos-latest"
+                }
+              ]
path: .github/workflows/test.yaml
user: login: Azaya89
body: I've removed the "exclude" step and it caused no problems. python 3.7 and 3.8 are not included in the `pixi.toml` file initially.
created_at: 2025-03-13T16:31:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,237 @@
+# Setting up a development environment
path: doc/developer_guide.md
user: login: Azaya89
body: LGTM!

![image](https://github.com/user-attachments/assets/891279f8-12bc-4c6d-8fe0-570412e5cba9)

created_at: 2025-03-13T16:32:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,237 @@
+# Setting up a development environment
+
+This guide describes how to install and configure the development environment for contributing to the colorcet repository.
+
+If you have any problems with the steps here, please reach out in the `dev` channel on [Discord](https://discord.gg/rb6gPXbdAr) or on [Discourse](https://discourse.holoviz.org/).
+
+## TL;DR
+
+0. Open an [issue on Github](https://github.com/holoviz/colorcet/issues) if needed
+1. Fork and clone [colorcet's Github repository](https://github.com/holoviz/colorcet)
+2. Install [`pixi`](https://pixi.sh)
+3. Run `pixi run setup-dev` to create your development environment
+4. Run `pixi shell` to activate the created environment
path: doc/developer_guide.md
user: login: hoxbro
body: You don't need to activate the environment to run the tasks. 
created_at: 2025-03-13T16:55:59Z
author_association: MEMBER
diff_hunk: @@ -8,58 +7,160 @@ on:
     branches:
       - "*"
   workflow_dispatch:
+    inputs:
+      target:
+        description: "How much of the test suite to run"
+        type: choice
+        default: default
+        options:
+          - default
+          - full
+      cache:
+        description: "Use cache"
+        type: boolean
+        default: true
+
   schedule:
     - cron: "0 9 * * SUN"
 
 concurrency:
   group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
   cancel-in-progress: true
 
+defaults:
+  run:
+    shell: bash -e {0}
+
+env:
+  DISPLAY: ":99.0"
+  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+  COV: "--cov=./colorcet --cov-report=xml"
+
 jobs:
   pre_commit:
     name: Run pre-commit
     runs-on: "ubuntu-latest"
     steps:
       - uses: holoviz-dev/holoviz_tasks/pre-commit@v0
-  test_suite:
-    name: Pytest on ${{ matrix.python-version }}, ${{ matrix.os }}
-    needs: [pre_commit]
+
+  setup:
+    name: Setup workflow
+    runs-on: ubuntu-latest
+    permissions:
+      pull-requests: read
+    outputs:
+      code_change: ${{ steps.filter.outputs.code }}
+      matrix: ${{ env.MATRIX }}
+    steps:
+      - uses: actions/checkout@v4
+        if: github.event_name != 'pull_request'
+      - name: Check for code changes
+        uses: dorny/paths-filter@v3
+        id: filter
+        with:
+          filters: |
+            code:
+              - 'colorcet/**'
+              - 'pixi.toml'
+              - 'pyproject.toml'
+              - '.github/workflows/test.yaml'
+      - name: Set matrix option
+        run: |
+          if [[ '${{ github.event_name }}' == 'workflow_dispatch' ]]; then
+            OPTION=${{ github.event.inputs.target }}
+          elif [[ '${{ github.event_name }}' == 'schedule' ]]; then
+            OPTION="full"
+          elif [[ '${{ github.event_name }}' == 'push' && '${{ github.ref_type }}' == 'tag' ]]; then
+            OPTION="full"
+          else
+            OPTION="default"
+          fi
+          echo "MATRIX_OPTION=$OPTION" >> $GITHUB_ENV
+      - name: Set test matrix with 'default' option
+        if: env.MATRIX_OPTION == 'default'
+        run: |
+          MATRIX=$(jq -nsc '{
+              "os": ["ubuntu-latest", "macos-latest", "windows-latest"],
+              "environment": ["test-39", "test-312"],
+              "exclude": [
+                {
+                "environment": "test-39",
+                "os": "macos-latest"
+                }
+              ]
path: .github/workflows/test.yaml
user: login: hoxbro
body: Can you try to see if it is possible to add it?
created_at: 2025-03-13T16:58:02Z
author_association: MEMBER
diff_hunk: @@ -1,5 +1,4 @@
 name: packages
path: .github/workflows/build.yaml
user: login: Azaya89
body: The conda part is failing :(

![image](https://github.com/user-attachments/assets/18ed500f-6596-4e2e-816e-50adf7ab25dd)

It works when I run `pixi run build-conda` locally though

created_at: 2025-03-13T17:11:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,5 +1,4 @@
 name: packages
path: .github/workflows/build.yaml
user: login: hoxbro
body: Replace file extension or change pkg_format in shell file. 
created_at: 2025-03-13T17:15:18Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,237 @@
+# Setting up a development environment
+
+This guide describes how to install and configure the development environment for contributing to the colorcet repository.
+
+If you have any problems with the steps here, please reach out in the `dev` channel on [Discord](https://discord.gg/rb6gPXbdAr) or on [Discourse](https://discourse.holoviz.org/).
+
+## TL;DR
+
+0. Open an [issue on Github](https://github.com/holoviz/colorcet/issues) if needed
+1. Fork and clone [colorcet's Github repository](https://github.com/holoviz/colorcet)
+2. Install [`pixi`](https://pixi.sh)
+3. Run `pixi run setup-dev` to create your development environment
+4. Run `pixi shell` to activate the created environment
path: doc/developer_guide.md
user: login: Azaya89
body: OK
created_at: 2025-03-13T17:16:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,5 +1,4 @@
 name: packages
path: .github/workflows/build.yaml
user: login: Azaya89
body: Works now. I replaced the file extension.

![image](https://github.com/user-attachments/assets/4773c5a0-8b4e-4cba-af3e-8867c149e887)

created_at: 2025-03-13T19:34:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -8,58 +7,160 @@ on:
     branches:
       - "*"
   workflow_dispatch:
+    inputs:
+      target:
+        description: "How much of the test suite to run"
+        type: choice
+        default: default
+        options:
+          - default
+          - full
+      cache:
+        description: "Use cache"
+        type: boolean
+        default: true
+
   schedule:
     - cron: "0 9 * * SUN"
 
 concurrency:
   group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
   cancel-in-progress: true
 
+defaults:
+  run:
+    shell: bash -e {0}
+
+env:
+  DISPLAY: ":99.0"
+  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+  COV: "--cov=./colorcet --cov-report=xml"
+
 jobs:
   pre_commit:
     name: Run pre-commit
     runs-on: "ubuntu-latest"
     steps:
       - uses: holoviz-dev/holoviz_tasks/pre-commit@v0
-  test_suite:
-    name: Pytest on ${{ matrix.python-version }}, ${{ matrix.os }}
-    needs: [pre_commit]
+
+  setup:
+    name: Setup workflow
+    runs-on: ubuntu-latest
+    permissions:
+      pull-requests: read
+    outputs:
+      code_change: ${{ steps.filter.outputs.code }}
+      matrix: ${{ env.MATRIX }}
+    steps:
+      - uses: actions/checkout@v4
+        if: github.event_name != 'pull_request'
+      - name: Check for code changes
+        uses: dorny/paths-filter@v3
+        id: filter
+        with:
+          filters: |
+            code:
+              - 'colorcet/**'
+              - 'pixi.toml'
+              - 'pyproject.toml'
+              - '.github/workflows/test.yaml'
+      - name: Set matrix option
+        run: |
+          if [[ '${{ github.event_name }}' == 'workflow_dispatch' ]]; then
+            OPTION=${{ github.event.inputs.target }}
+          elif [[ '${{ github.event_name }}' == 'schedule' ]]; then
+            OPTION="full"
+          elif [[ '${{ github.event_name }}' == 'push' && '${{ github.ref_type }}' == 'tag' ]]; then
+            OPTION="full"
+          else
+            OPTION="default"
+          fi
+          echo "MATRIX_OPTION=$OPTION" >> $GITHUB_ENV
+      - name: Set test matrix with 'default' option
+        if: env.MATRIX_OPTION == 'default'
+        run: |
+          MATRIX=$(jq -nsc '{
+              "os": ["ubuntu-latest", "macos-latest", "windows-latest"],
+              "environment": ["test-39", "test-312"],
+              "exclude": [
+                {
+                "environment": "test-39",
+                "os": "macos-latest"
+                }
+              ]
path: .github/workflows/test.yaml
user: login: Azaya89
body: i've successfully added for 3.8 but conda can't solve for Python 3.7 build for osx‑arm64. So I'm thinking if I should only add 3.8?
created_at: 2025-03-13T20:19:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -8,58 +7,160 @@ on:
     branches:
       - "*"
   workflow_dispatch:
+    inputs:
+      target:
+        description: "How much of the test suite to run"
+        type: choice
+        default: default
+        options:
+          - default
+          - full
+      cache:
+        description: "Use cache"
+        type: boolean
+        default: true
+
   schedule:
     - cron: "0 9 * * SUN"
 
 concurrency:
   group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
   cancel-in-progress: true
 
+defaults:
+  run:
+    shell: bash -e {0}
+
+env:
+  DISPLAY: ":99.0"
+  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+  COV: "--cov=./colorcet --cov-report=xml"
+
 jobs:
   pre_commit:
     name: Run pre-commit
     runs-on: "ubuntu-latest"
     steps:
       - uses: holoviz-dev/holoviz_tasks/pre-commit@v0
-  test_suite:
-    name: Pytest on ${{ matrix.python-version }}, ${{ matrix.os }}
-    needs: [pre_commit]
+
+  setup:
+    name: Setup workflow
+    runs-on: ubuntu-latest
+    permissions:
+      pull-requests: read
+    outputs:
+      code_change: ${{ steps.filter.outputs.code }}
+      matrix: ${{ env.MATRIX }}
+    steps:
+      - uses: actions/checkout@v4
+        if: github.event_name != 'pull_request'
+      - name: Check for code changes
+        uses: dorny/paths-filter@v3
+        id: filter
+        with:
+          filters: |
+            code:
+              - 'colorcet/**'
+              - 'pixi.toml'
+              - 'pyproject.toml'
+              - '.github/workflows/test.yaml'
+      - name: Set matrix option
+        run: |
+          if [[ '${{ github.event_name }}' == 'workflow_dispatch' ]]; then
+            OPTION=${{ github.event.inputs.target }}
+          elif [[ '${{ github.event_name }}' == 'schedule' ]]; then
+            OPTION="full"
+          elif [[ '${{ github.event_name }}' == 'push' && '${{ github.ref_type }}' == 'tag' ]]; then
+            OPTION="full"
+          else
+            OPTION="default"
+          fi
+          echo "MATRIX_OPTION=$OPTION" >> $GITHUB_ENV
+      - name: Set test matrix with 'default' option
+        if: env.MATRIX_OPTION == 'default'
+        run: |
+          MATRIX=$(jq -nsc '{
+              "os": ["ubuntu-latest", "macos-latest", "windows-latest"],
+              "environment": ["test-39", "test-312"],
+              "exclude": [
+                {
+                "environment": "test-39",
+                "os": "macos-latest"
+                }
+              ]
path: .github/workflows/test.yaml
user: login: hoxbro
body: I will let you decide
created_at: 2025-03-14T07:26:05Z
author_association: MEMBER
diff_hunk: @@ -8,58 +7,160 @@ on:
     branches:
       - "*"
   workflow_dispatch:
+    inputs:
+      target:
+        description: "How much of the test suite to run"
+        type: choice
+        default: default
+        options:
+          - default
+          - full
+      cache:
+        description: "Use cache"
+        type: boolean
+        default: true
+
   schedule:
     - cron: "0 9 * * SUN"
 
 concurrency:
   group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
   cancel-in-progress: true
 
+defaults:
+  run:
+    shell: bash -e {0}
+
+env:
+  DISPLAY: ":99.0"
+  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+  COV: "--cov=./colorcet --cov-report=xml"
+
 jobs:
   pre_commit:
     name: Run pre-commit
     runs-on: "ubuntu-latest"
     steps:
       - uses: holoviz-dev/holoviz_tasks/pre-commit@v0
-  test_suite:
-    name: Pytest on ${{ matrix.python-version }}, ${{ matrix.os }}
-    needs: [pre_commit]
+
+  setup:
+    name: Setup workflow
+    runs-on: ubuntu-latest
+    permissions:
+      pull-requests: read
+    outputs:
+      code_change: ${{ steps.filter.outputs.code }}
+      matrix: ${{ env.MATRIX }}
+    steps:
+      - uses: actions/checkout@v4
+        if: github.event_name != 'pull_request'
+      - name: Check for code changes
+        uses: dorny/paths-filter@v3
+        id: filter
+        with:
+          filters: |
+            code:
+              - 'colorcet/**'
+              - 'pixi.toml'
+              - 'pyproject.toml'
+              - '.github/workflows/test.yaml'
+      - name: Set matrix option
+        run: |
+          if [[ '${{ github.event_name }}' == 'workflow_dispatch' ]]; then
+            OPTION=${{ github.event.inputs.target }}
+          elif [[ '${{ github.event_name }}' == 'schedule' ]]; then
+            OPTION="full"
+          elif [[ '${{ github.event_name }}' == 'push' && '${{ github.ref_type }}' == 'tag' ]]; then
+            OPTION="full"
+          else
+            OPTION="default"
+          fi
+          echo "MATRIX_OPTION=$OPTION" >> $GITHUB_ENV
+      - name: Set test matrix with 'default' option
+        if: env.MATRIX_OPTION == 'default'
+        run: |
+          MATRIX=$(jq -nsc '{
+              "os": ["ubuntu-latest", "macos-latest", "windows-latest"],
+              "environment": ["test-39", "test-312"],
+              "exclude": [
+                {
+                "environment": "test-39",
+                "os": "macos-latest"
+                }
+              ]
path: .github/workflows/test.yaml
user: login: hoxbro
body: What did you decide?
created_at: 2025-03-14T11:11:55Z
author_association: MEMBER
diff_hunk: @@ -12,62 +11,132 @@ on:
   schedule:
     - cron: '0 9 * * SUN'
 
+env:
+  PYTHON_VERSION: "3.11"
+  PACKAGE: "colorcet"
+
+defaults:
+  run:
+    shell: bash -e {0}
+
 jobs:
+  waiting_room:
+    name: Waiting Room
+    runs-on: ubuntu-latest
+    needs: [conda_build, pip_install]
+    if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
+    environment:
+      name: publish
+    steps:
+      - run: echo "All builds have finished, have been approved, and ready to publish"
+
+  pixi_lock:
+    name: Pixi lock
+    runs-on: ubuntu-latest
+    steps:
+      - uses: holoviz-dev/holoviz_tasks/pixi_lock@v0
+
   conda_build:
-    name: Build Conda Packages
-    runs-on: 'ubuntu-latest'
+    name: Build Conda
+    needs: [pixi_lock]
+    runs-on: "ubuntu-latest"
+    steps:
+      - uses: holoviz-dev/holoviz_tasks/pixi_install@v0
+        with:
+          environments: "build"
+          download-data: false
+          install: false
+      - name: conda build
+        run: pixi run -e build build-conda
+      - uses: actions/upload-artifact@v4
+        if: always()
+        with:
+          name: conda
+          path: dist/*.tar.bz2
+          if-no-files-found: error
+
+  conda-publish:
+    name: Publish Conda
+    runs-on: ubuntu-latest
+    needs: [conda_build, waiting_room]
+    if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
     defaults:
       run:
-        shell: bash -l {0}
+        shell: bash -el {0}
     steps:
-      - uses: actions/checkout@v4
-      - name: Fetch unshallow
-        run: git fetch --prune --tags --unshallow -f
-      - uses: conda-incubator/setup-miniconda@v2
+      - uses: actions/download-artifact@v4
+        with:
+          name: conda
+          path: dist/
+      - name: Set environment variables
+        run: |
+          echo "TAG=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
+          echo "CONDA_FILE=$(ls dist/*.conda)" >> $GITHUB_ENV
path: .github/workflows/build.yaml
user: login: hoxbro
body: You didn't change this
created_at: 2025-03-14T11:13:17Z
author_association: MEMBER
diff_hunk: @@ -12,62 +11,132 @@ on:
   schedule:
     - cron: '0 9 * * SUN'
 
+env:
+  PYTHON_VERSION: "3.11"
+  PACKAGE: "colorcet"
+
+defaults:
+  run:
+    shell: bash -e {0}
+
 jobs:
+  waiting_room:
+    name: Waiting Room
+    runs-on: ubuntu-latest
+    needs: [conda_build, pip_install]
+    if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
+    environment:
+      name: publish
+    steps:
+      - run: echo "All builds have finished, have been approved, and ready to publish"
+
+  pixi_lock:
+    name: Pixi lock
+    runs-on: ubuntu-latest
+    steps:
+      - uses: holoviz-dev/holoviz_tasks/pixi_lock@v0
+
   conda_build:
-    name: Build Conda Packages
-    runs-on: 'ubuntu-latest'
+    name: Build Conda
+    needs: [pixi_lock]
+    runs-on: "ubuntu-latest"
+    steps:
+      - uses: holoviz-dev/holoviz_tasks/pixi_install@v0
+        with:
+          environments: "build"
+          download-data: false
+          install: false
+      - name: conda build
+        run: pixi run -e build build-conda
+      - uses: actions/upload-artifact@v4
+        if: always()
+        with:
+          name: conda
+          path: dist/*.tar.bz2
+          if-no-files-found: error
+
+  conda-publish:
+    name: Publish Conda
+    runs-on: ubuntu-latest
+    needs: [conda_build, waiting_room]
+    if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
     defaults:
       run:
-        shell: bash -l {0}
+        shell: bash -el {0}
     steps:
-      - uses: actions/checkout@v4
-      - name: Fetch unshallow
-        run: git fetch --prune --tags --unshallow -f
-      - uses: conda-incubator/setup-miniconda@v2
+      - uses: actions/download-artifact@v4
+        with:
+          name: conda
+          path: dist/
+      - name: Set environment variables
+        run: |
+          echo "TAG=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
+          echo "CONDA_FILE=$(ls dist/*.conda)" >> $GITHUB_ENV
path: .github/workflows/build.yaml
user: login: Azaya89
body: Arrggggsh!
created_at: 2025-03-14T14:45:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -8,58 +7,160 @@ on:
     branches:
       - "*"
   workflow_dispatch:
+    inputs:
+      target:
+        description: "How much of the test suite to run"
+        type: choice
+        default: default
+        options:
+          - default
+          - full
+      cache:
+        description: "Use cache"
+        type: boolean
+        default: true
+
   schedule:
     - cron: "0 9 * * SUN"
 
 concurrency:
   group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
   cancel-in-progress: true
 
+defaults:
+  run:
+    shell: bash -e {0}
+
+env:
+  DISPLAY: ":99.0"
+  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+  COV: "--cov=./colorcet --cov-report=xml"
+
 jobs:
   pre_commit:
     name: Run pre-commit
     runs-on: "ubuntu-latest"
     steps:
       - uses: holoviz-dev/holoviz_tasks/pre-commit@v0
-  test_suite:
-    name: Pytest on ${{ matrix.python-version }}, ${{ matrix.os }}
-    needs: [pre_commit]
+
+  setup:
+    name: Setup workflow
+    runs-on: ubuntu-latest
+    permissions:
+      pull-requests: read
+    outputs:
+      code_change: ${{ steps.filter.outputs.code }}
+      matrix: ${{ env.MATRIX }}
+    steps:
+      - uses: actions/checkout@v4
+        if: github.event_name != 'pull_request'
+      - name: Check for code changes
+        uses: dorny/paths-filter@v3
+        id: filter
+        with:
+          filters: |
+            code:
+              - 'colorcet/**'
+              - 'pixi.toml'
+              - 'pyproject.toml'
+              - '.github/workflows/test.yaml'
+      - name: Set matrix option
+        run: |
+          if [[ '${{ github.event_name }}' == 'workflow_dispatch' ]]; then
+            OPTION=${{ github.event.inputs.target }}
+          elif [[ '${{ github.event_name }}' == 'schedule' ]]; then
+            OPTION="full"
+          elif [[ '${{ github.event_name }}' == 'push' && '${{ github.ref_type }}' == 'tag' ]]; then
+            OPTION="full"
+          else
+            OPTION="default"
+          fi
+          echo "MATRIX_OPTION=$OPTION" >> $GITHUB_ENV
+      - name: Set test matrix with 'default' option
+        if: env.MATRIX_OPTION == 'default'
+        run: |
+          MATRIX=$(jq -nsc '{
+              "os": ["ubuntu-latest", "macos-latest", "windows-latest"],
+              "environment": ["test-39", "test-312"],
+              "exclude": [
+                {
+                "environment": "test-39",
+                "os": "macos-latest"
+                }
+              ]
path: .github/workflows/test.yaml
user: login: Azaya89
body: I added 3.8 alone
created_at: 2025-03-14T16:25:21Z
author_association: CONTRIBUTOR

PR comments:
user: login: codecov[bot]
created_at: 2025-03-12T09:59:55Z
body: ## [Codecov](https://app.codecov.io/gh/holoviz/colorcet/pull/128?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=holoviz) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 95.89%. Comparing base [(`34b3992`)](https://app.codecov.io/gh/holoviz/colorcet/commit/34b3992aee512541e445863f2d97dec6149ce64d?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=holoviz) to head [(`5f3f9c6`)](https://app.codecov.io/gh/holoviz/colorcet/commit/5f3f9c6fee77252243bec54f22055915238e9e3f?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=holoviz).
> Report is 5 commits behind head on main.

<details><summary>Additional details and impacted files</summary>


```diff
@@             Coverage Diff             @@
##             main     #128       +/-   ##
===========================================
+ Coverage   85.70%   95.89%   +10.19%     
===========================================
  Files           8        6        -2     
  Lines        1938     1609      -329     
===========================================
- Hits         1661     1543      -118     
+ Misses        277       66      -211     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/holoviz/colorcet/pull/128?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=holoviz).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=holoviz).

<details><summary>🚀 New features to boost your workflow: </summary>

- ❄ [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>
author_association: NONE
user: login: hoxbro
created_at: 2025-03-14T07:27:29Z
body: I don't think you have pushed the changes to this PR. 
author_association: MEMBER
user: login: Azaya89
created_at: 2025-03-14T10:59:06Z
body: > I don't think you have pushed the changes to this PR.

Done now.
author_association: CONTRIBUTOR
user: login: Azaya89
created_at: 2025-03-14T17:54:00Z
body: I think everything is fine now...
author_association: CONTRIBUTOR
user: login: hoxbro
created_at: 2025-03-14T18:22:55Z
body: PyPi publish step failed: https://github.com/holoviz/colorcet/actions/runs/13862842237/job/38795500998
author_association: MEMBER
user: login: hoxbro
created_at: 2025-03-14T18:33:54Z
body: Fixed in https://github.com/holoviz/colorcet/pull/129
author_association: MEMBER
user: login: hoxbro
created_at: 2025-03-14T18:41:42Z
body: Other than that, everything went great with a dev release.

Great job!
author_association: MEMBER
user: login: Azaya89
created_at: 2025-03-14T19:48:59Z
body: Thank you for the help!
author_association: CONTRIBUTOR