diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index d271bc8b4..000000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,229 +0,0 @@ -# CircleCI configuration file -# -# Check https://circleci.com/docs/2.0/language-python/ for more details -# -version: 2.1 - -orbs: - codecov: codecov/codecov@3.2.3 - -references: - restore_keys: &restore_keys - keys: - - python-env-v1-{{ arch }}-{{ .Environment.CIRCLE_JOB }}-{{ checksum "setup.py" }}-{{ checksum "requirements/requirements-test.txt" }}-{{ checksum ".circleci/ci-oldest-reqs.txt" }} - - save_key: &save_key - key: python-env-v1-{{ arch }}-{{ .Environment.CIRCLE_JOB }}-{{ checksum "setup.py" }}-{{ checksum "requirements/requirements-test.txt" }}-{{ checksum ".circleci/ci-oldest-reqs.txt" }} - -jobs: - linux-python-311: &test-template - docker: - - image: cimg/python:3.11 - - environment: - DEPENDENCIES: "NEWEST" - SIGNAC_VERSION: "signac" - PYTHON: python - - working_directory: ~/repo - - steps: - - checkout - - - run: - name: Install dependencies - command: | - ${PYTHON} -m pip install --progress-bar off -U virtualenv --user - mkdir -p ./venv - ${PYTHON} -m virtualenv ./venv --clear - . venv/bin/activate - ${PYTHON} -m pip install --progress-bar off -U pip>=20.3 - ${PYTHON} -m pip install --progress-bar off ${SIGNAC_VERSION} - # DEPENDENCIES can be "OLDEST" or "NEWEST" - if [ "${DEPENDENCIES}" == "OLDEST" ]; then - ${PYTHON} -m pip install --progress-bar off -r .circleci/ci-oldest-reqs.txt - else - ${PYTHON} -m pip install --progress-bar off -r requirements.txt - ${PYTHON} -m pip install --progress-bar off -r requirements/requirements-test.txt - fi - - - run: - name: Run tests - command: | - . venv/bin/activate - ${PYTHON} -m pytest --cov=flow --cov-config=setup.cfg --cov-report=xml tests/ -v - - - store_artifacts: - path: test-reports - destination: test-reports - - linux-python-311-signac-latest: - <<: *test-template - environment: - DEPENDENCIES: "NEWEST" - SIGNAC_VERSION: "git+ssh://git@github.com/glotzerlab/signac.git" - PYTHON: python - linux-python-310: - <<: *test-template - docker: - - image: cimg/python:3.10 - linux-python-39: - <<: *test-template - docker: - - image: cimg/python:3.9 - linux-python-38: - <<: *test-template - docker: - - image: cimg/python:3.8 - linux-python-38-oldest: - <<: *test-template - docker: - - image: cimg/python:3.8 - environment: - DEPENDENCIES: "OLDEST" - SIGNAC_VERSION: "signac==1.8.0" - PYTHON: python - - test-install-pip-python-311: - docker: - - image: cimg/python:3.11 - - environment: - PYTHON: python - - steps: - - - run: - name: install-with-pip - command: | - ${PYTHON} -m pip install --progress-bar off signac signac-flow - - - run: &smoke-test - name: smoke-test - command: | - ${PYTHON} -m signac --version - ${PYTHON} -c 'import signac' - ${PYTHON} -m flow --version - ${PYTHON} -c 'import flow' - - test-install-conda: &test-install-conda - environment: - # The default job does not specify the version, just like the - # instructions. - PYTHON_DEP: "" - PYTHON: python - docker: - - image: conda/miniconda3:latest - - steps: - - - run: - name: install-with-conda - command: | - conda install -c conda-forge signac signac-flow ${PYTHON_DEP} --yes - - - run: - <<: *smoke-test - - test-install-conda-python-311: - <<: *test-install-conda - environment: - PYTHON_DEP: "python=3.11" - PYTHON: python - - check-metadata: - docker: - - image: cimg/python:3.11 - - working_directory: ~/repo - - steps: - - checkout - - - run: - name: install-dev-requirements - command: | - pip install --user -U -r requirements/requirements-test.txt - - - run: - name: check-citation-metadata - command: | - ./.sync-zenodo-metadata.py --check > /dev/null - - test-deploy-pypi: - docker: - - image: cimg/python:3.11 - working_directory: ~/repo - steps: - - checkout - - run: - name: test-deploy-pypi - command: | - bash .circleci/deploy.bash testpypi - - deploy-pypi: - docker: - - image: cimg/python:3.11 - working_directory: ~/repo - steps: - - checkout - - run: - name: deploy-pypi - command: | - bash .circleci/deploy.bash pypi - - -workflows: - version: 2 - test: - jobs: - - linux-python-311: - post-steps: - - codecov/upload - - linux-python-310: - post-steps: - - codecov/upload - - linux-python-39: - post-steps: - - codecov/upload - - linux-python-38: - post-steps: - - codecov/upload - - linux-python-38-oldest: - post-steps: - - codecov/upload - - check-metadata: - filters: - branches: - only: /release\/.*/ - - test-deploy-pypi: - filters: - branches: - only: /release\/.*/ - requires: - - linux-python-311 - - linux-python-310 - - linux-python-39 - - linux-python-38 - - linux-python-38-oldest - nightly: - triggers: - - schedule: - cron: "0 0 * * *" - filters: - branches: - only: - - master - jobs: - - linux-python-311-signac-latest - - test-install-pip-python-311 - - test-install-conda - - test-install-conda-python-311 - deploy: - jobs: - - deploy-pypi: - filters: - branches: - ignore: /.*/ - tags: - only: /v.*/ diff --git a/.circleci/deploy.bash b/.circleci/deploy.bash deleted file mode 100755 index 20b0f94e3..000000000 --- a/.circleci/deploy.bash +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/bash - -set -e -set -u - -python -m pip install --progress-bar off --user -U -r requirements/requirements-test.txt -python -m pip install --progress-bar off --user -U twine wheel setuptools - -# PYPI_API_TOKEN - (Required, Secret) Token for the publisher's account on PyPI -# TEST_PYPI_API_TOKEN - (Required, Secret) Token for the publisher's account on TestPyPI - -cat << EOF > ~/.pypirc -[distutils] -index-servers= - pypi - testpypi - -[pypi] -username: __token__ -password: ${PYPI_API_TOKEN} - -[testpypi] -repository: https://test.pypi.org/legacy/ -username: __token__ -password: ${TEST_PYPI_API_TOKEN} -EOF - -# Create wheels and source distribution -python setup.py bdist_wheel -python setup.py sdist - -# Test generated wheel -python -m pip install signac-flow --progress-bar off -U --force-reinstall -f dist/ -python -m pytest tests/ -v - -# Upload wheels -if [[ "$1" == "testpypi" || "$1" == "pypi" ]]; then - python -m twine upload --skip-existing --repository $1 dist/* -else - echo "A valid repository must be provided: pypi or testpypi." - exit 1 -fi diff --git a/.circleci/ci-oldest-reqs.txt b/.github/workflows/ci-oldest-reqs.txt similarity index 100% rename from .circleci/ci-oldest-reqs.txt rename to .github/workflows/ci-oldest-reqs.txt diff --git a/.github/workflows/deploy-pypi.yml b/.github/workflows/deploy-pypi.yml new file mode 100644 index 000000000..b1a4bdf11 --- /dev/null +++ b/.github/workflows/deploy-pypi.yml @@ -0,0 +1,18 @@ +name: Publish to PyPI + +on: + push: + tags: + - 'v*.*.*' + +concurrency: + group: "${{ github.workflow }}-${{ github.ref }}" + cancel-in-progress: true + +jobs: + build-and-test-sdist-and-wheels: + uses: ./.github/workflows/publish-packages.yml + with: + upload_to_test: false + secrets: + PYPI_API_TOKEN: ${{ secrets.PYPI_API_TOKEN }} diff --git a/.github/workflows/deploy-test-pypi.yml b/.github/workflows/deploy-test-pypi.yml new file mode 100644 index 000000000..d1fe98d94 --- /dev/null +++ b/.github/workflows/deploy-test-pypi.yml @@ -0,0 +1,18 @@ +name: Publish to TestPyPI + +on: + push: + branches: + - 'release/*.*.*' + +concurrency: + group: "${{ github.workflow }}-${{ github.ref }}" + cancel-in-progress: true + +jobs: + build-and-test-sdist-and-wheels: + uses: ./.github/workflows/publish-packages.yml + with: + upload_to_test: true + secrets: + TEST_PYPI_API_TOKEN: ${{ secrets.TEST_PYPI_API_TOKEN }} diff --git a/.github/workflows/publish-packages.yml b/.github/workflows/publish-packages.yml new file mode 100644 index 000000000..d07354a04 --- /dev/null +++ b/.github/workflows/publish-packages.yml @@ -0,0 +1,72 @@ +name: Publish packages + +on: + workflow_call: + inputs: + upload_to_test: + required: true + type: boolean + secrets: + TEST_PYPI_API_TOKEN: + required: false + PYPI_API_TOKEN: + required: false + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Check out repo + uses: actions/checkout@v3 + with: + submodules: "recursive" + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.11" + - name: Install dependencies + run: | + # We must explicitly install the requirements so that we can force + # installation of the local wheel below in case the version conflicts + # with published wheels (typically only possible during testing). + python -m pip install \ + -r requirements.txt \ + -r requirements-test.txt + - name: Install pypa/build + run: + python -m pip install build + - name: Build a binary wheel and a source tarball + run: + python -m build --sdist --wheel --outdir dist/ . + - name: Install wheel + run: + python -m pip install signac-flow --progress-bar off --no-index -f dist/ + - name: Test with pytest + run: + python -m pytest -v tests/ + - name: Upload artifact + uses: actions/upload-artifact@v2 + with: + name: release + path: dist/ + + publish: + needs: [build] + runs-on: ubuntu-latest + steps: + - name: Download artifact + uses: actions/download-artifact@v2 + with: + name: release + path: dist/ + - name: Publish package to TestPyPI + if: ${{ inputs.upload_to_test }} + uses: pypa/gh-action-pypi-publish@release/v1 + with: + repository_url: https://test.pypi.org/legacy/ + password: ${{ secrets.TEST_PYPI_API_TOKEN }} + - name: Publish package to PyPI + if: ${{ !inputs.upload_to_test }} + uses: pypa/gh-action-pypi-publish@release/v1 + with: + password: ${{ secrets.PYPI_API_TOKEN }} diff --git a/.github/workflows/run-pytest.yml b/.github/workflows/run-pytest.yml new file mode 100644 index 000000000..502b2feff --- /dev/null +++ b/.github/workflows/run-pytest.yml @@ -0,0 +1,55 @@ +name: Run Unit Tests + +on: + # trigger on pull requests + pull_request: + + # trigger on all commits to master + push: + branches: + - 'master' + + # trigger on request + workflow_dispatch: +concurrency: + group: "${{ github.workflow }}-${{ github.ref }}" + cancel-in-progress: true +jobs: + test: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest] + config: [ {python: '3.8', dependencies: 'newest'}, + {python: '3.9', dependencies: 'newest'}, + {python: '3.10', dependencies: 'newest'}, + {python: '3.11', dependencies: 'newest'}, + {python: '3.8', dependencies: 'oldest'} ] + steps: + - uses: actions/checkout@v3 + with: + submodules: "recursive" + - name: Set up Python ${{ matrix.config.python }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.config.python }} + - name: Install newest dependencies + run: | + pip install -r requirements/requirements-test.txt + if: ${{ matrix.config.dependencies == 'newest' }} + - name: Install oldest supported dependencies + # To prevent Dependabot from updating the pinnings in this "oldest" + # dependency list, we have to avoid the word "requirements" in the + # filename. That's why it is in the .github/ directory and named "reqs" + # instead of "requirements." + run: | + pip install -r .github/workflows/ci-oldest-reqs.txt + if: ${{ matrix.config.dependencies == 'oldest' }} + - name: Install the package + run: | + pip install -e . + - name: Test with pytest + run: | + pytest --cov=flow --cov-config=setup.cfg --cov-report=xml tests/ -v + - uses: codecov/codecov-action@v3 diff --git a/changelog.txt b/changelog.txt index 0d636ea0d..8a94d2908 100644 --- a/changelog.txt +++ b/changelog.txt @@ -15,6 +15,7 @@ Changed +++++++ - Placing ``@FlowProject.pre`` and ``@FlowProject.post`` before the ``FlowProject.operation`` decorator raises an error (#700). +- Updated CI to use GitHub Actions (#698). Removed +++++++