diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 03671ebb..ddfc2375 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -21,30 +21,51 @@ on: jobs: - package: - name: Build package + conda-package: + name: Build Conda package runs-on: "ubuntu-latest" steps: - uses: actions/checkout@v3 with: fetch-depth: 0 - - uses: conda-incubator/setup-miniconda@v2 - with: - miniconda-version: "latest" - activate-environment: build-conda-token - environment-file: etc/build-environment.yml - python-version: 3.8 - auto-activate-base: false + - name: Create build environment + run: | + source $CONDA/bin/activate + conda env create -f etc/build-environment.yml - name: conda Build - shell: bash -l {0} run: | - VERSION=`python -m setuptools_scm` conda build conda.recipe - mv $CONDA_PREFIX/conda-bld . + source $CONDA/bin/activate && conda activate build-conda-project + VERSION=`hatch version` conda build -c conda-forge --output-folder conda-build conda.recipe - name: Upload the build artifact uses: actions/upload-artifact@v3 with: name: package-${{ github.sha }} - path: conda-bld + path: conda-build + + build-wheel: + name: Build the wheel + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 + with: + fetch-depth: 0 + - name: Setup Python + uses: actions/setup-python@65d7f2d534ac1bc67fcd62888c5f4f3d2cb2b236 # v4 + with: + python-version: "3.10" + - name: Install build dependencies + run: pip install build + - name: Build the package + run: python -m build + - name: Upload the build artifact + uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3 + with: + name: wheel-${{ github.sha }} + path: dist/*.whl + if-no-files-found: error + retention-days: 7 + test: name: Test (conda ${{ matrix.conda-version }}, Python ${{ matrix.python-version }}, ${{ matrix.os }}) runs-on: ${{ matrix.os }} @@ -81,14 +102,6 @@ jobs: shell: bash run: | ./conda.exe create -p $HOME/miniconda conda=${{ matrix.conda-version }} python=${{ matrix.python-version }} - - name: Update with test dependencies - shell: bash - run: | - if [ $RUNNER_OS == 'Windows' ]; then - source $HOME/miniconda/Scripts/activate root && conda env update -f etc/test-environment.yml -p $HOME/miniconda && $HOME/miniconda/Scripts/pip install --no-deps . - else - source $HOME/miniconda/bin/activate root && conda env update -f etc/test-environment.yml -p $HOME/miniconda && $HOME/miniconda/bin/pip install --no-deps . - fi - name: Install Libmamba shell: bash run: | @@ -101,6 +114,14 @@ jobs: conda install conda-libmamba-solver -p $HOME/miniconda fi fi + - name: Update with test dependencies + shell: bash + run: | + if [ $RUNNER_OS == 'Windows' ]; then + source $HOME/miniconda/Scripts/activate root && conda env update -f etc/test-environment.yml -p $HOME/miniconda && $HOME/miniconda/Scripts/pip install --no-deps . + else + source $HOME/miniconda/bin/activate root && conda env update -f etc/test-environment.yml -p $HOME/miniconda && $HOME/miniconda/bin/pip install --no-deps . + fi - name: py.test shell: bash env: @@ -154,6 +175,30 @@ jobs: uses: glassechidna/artifact-cleaner@master with: minimumAge: 86400 + + publish-to-pypi: + name: Build & publish to PyPI + if: github.event_name == 'push' && github.event_name == 'release' && github.event.action == 'created' + runs-on: ubuntu-latest + needs: [check] + steps: + - name: Checkout + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 + - name: Setup Python + uses: actions/setup-python@65d7f2d534ac1bc67fcd62888c5f4f3d2cb2b236 # v4 + - name: Download the build artifacts + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3 + with: + name: wheel-${{ github.sha }} + path: ~/dist + - name: Install build dependencies + run: pip install twine + - name: Upload to PyPI with twine + run: python -m twine upload ~/dist/* + env: + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN}} + # This check job runs to ensure all tests have passed, such that we can use it as a "wildcard" for branch # protection to ensure all tests pass before a PR can be merged. check: diff --git a/conda.recipe/meta.yaml b/conda.recipe/meta.yaml index 4463e231..41998452 100644 --- a/conda.recipe/meta.yaml +++ b/conda.recipe/meta.yaml @@ -12,7 +12,7 @@ source: path: .. build: - script: {{ PYTHON }} -m pip install . -vv + script: SETUPTOOLS_SCM_PRETEND_VERSION={{version}} {{ PYTHON }} -m pip install . -vv noarch: python entry_points: {% for name, reference in project['scripts'].items() %} @@ -23,10 +23,12 @@ requirements: host: - python {{ project['requires-python'] }} - pip - - setuptools + {% for dep in pyproject['build-system']['requires'] %} + - {{ dep.lower() }} + {% endfor %} run: - python {{ project['requires-python'] }} - - conda-lock >=1.2 + - conda-lock >=2.2 - lockfile - pexpect - ruamel.yaml @@ -40,9 +42,9 @@ test: imports: - conda_project commands: - - conda-project --help - - conda-project --version - - python -c "import conda_project; ver = conda_project.__version__; assert ver != '0.0.0' and ver != 'unknown'" + # conda-project --help + # conda-project --version + - python -c "from conda_project import __version__; assert __version__ == \"{{ version }}\"" about: home: {{ project['urls']['repository'] }} diff --git a/environment.yml b/environment.yml index debf36ba..78c883f2 100644 --- a/environment.yml +++ b/environment.yml @@ -1,5 +1,4 @@ channels: - - defaults - conda-forge dependencies: - python=3.8 @@ -10,9 +9,16 @@ dependencies: - pytest-cov - pytest-mock - pre-commit - - conda-lock>=1.2 + - conda-lock>=2.2 - pydantic - ruamel.yaml - - setuptools-scm + - setuptools-scm>=6.2 + - shellingham + - python-dotenv + - lockfile + - pexpect - fsspec - python-libarchive-c + - pip + - pip: + - -e . diff --git a/etc/build-environment.yml b/etc/build-environment.yml index 337d4873..37c5e484 100644 --- a/etc/build-environment.yml +++ b/etc/build-environment.yml @@ -1,6 +1,12 @@ name: build-conda-project +channels: + - defaults + - conda-forge dependencies: - conda - conda-build - conda-verify + - hatch + - hatchling + - hatch-vcs - setuptools-scm diff --git a/etc/test-environment.yml b/etc/test-environment.yml index 7880d9b5..983e4d81 100644 --- a/etc/test-environment.yml +++ b/etc/test-environment.yml @@ -1,9 +1,8 @@ name: test-conda-project channels: - - defaults - conda-forge dependencies: - - conda-lock>=2.1.1 + - conda-lock>=2.2 - pexpect - lockfile - ruamel.yaml diff --git a/pyproject.toml b/pyproject.toml index 0b49cb65..c8fa41d2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [build-system] -requires = ["setuptools>=42", "wheel", "setuptools-scm[toml]>=6.2"] -build-backend = "setuptools.build_meta" +build-backend = "hatchling.build" +requires = ["hatchling", "hatch-vcs>=0.3", "setuptools-scm>=7.1"] [project] name = "conda-project" @@ -31,7 +31,7 @@ classifiers = [ "Topic :: Utilities", ] dependencies = [ - "conda-lock >=1.2", + "conda-lock >=2.2", "lockfile", "pexpect", "ruamel.yaml", @@ -42,9 +42,20 @@ dependencies = [ "libarchive-c" ] -[tool.setuptools_scm] +[tool.hatch.version] +source = "vcs" + +[tool.hatch.build.hooks.vcs] +version-file = "src/conda_project/_version.py" + +[tool.hatch.version.raw-options] version_scheme = "post-release" -write_to = "src/conda_project/_version.py" + +[tool.hatch.build.targets.sdist] +include = [ + "/src/conda_project", + "/pyproject.toml" +] [project.optional-dependencies] docs = [ diff --git a/src/conda_project/project.py b/src/conda_project/project.py index e1a565c1..a06c4fde 100644 --- a/src/conda_project/project.py +++ b/src/conda_project/project.py @@ -30,7 +30,13 @@ render_lockfile_for_platform, ) from fsspec.core import split_protocol -from pydantic import BaseModel, create_model + +try: + # Version 2 provides a v1 API + from pydantic.v1 import BaseModel, create_model +except ImportError: + from pydantic import BaseModel # type: ignore + from pydantic import create_model # type: ignore from .conda import ( CONDA_EXE, diff --git a/src/conda_project/project_file.py b/src/conda_project/project_file.py index 210c6fec..4b3c0fc7 100644 --- a/src/conda_project/project_file.py +++ b/src/conda_project/project_file.py @@ -9,9 +9,16 @@ from conda_lock._vendor.conda.models.match_spec import MatchSpec from pkg_resources import Requirement -from pydantic import BaseModel, ValidationError, validator from ruamel.yaml import YAML +try: + # Version 2 provides a v1 API + from pydantic.v1 import BaseModel, ValidationError, validator +except ImportError: + from pydantic import BaseModel # type: ignore + from pydantic import ValidationError # type: ignore + from pydantic import validator # type: ignore + from .exceptions import CondaProjectError PROJECT_YAML_FILENAMES = ("conda-project.yml", "conda-project.yaml") diff --git a/tests/test_project_file.py b/tests/test_project_file.py index 516bd947..73a895ff 100644 --- a/tests/test_project_file.py +++ b/tests/test_project_file.py @@ -7,7 +7,12 @@ from typing import Dict, List, Optional, Union import pytest -from pydantic import ValidationError + +try: + # Version 2 provides a v1 API + from pydantic.v1 import ValidationError +except ImportError: + from pydantic import ValidationError # type: ignore from conda_project.exceptions import CondaProjectError from conda_project.project_file import (