diff --git a/.github/workflows/_build_and_publish_documentation.yml b/.github/workflows/_build_and_publish_documentation.yml new file mode 100644 index 0000000..e89e8f9 --- /dev/null +++ b/.github/workflows/_build_and_publish_documentation.yml @@ -0,0 +1,110 @@ +name: Build and publish documentation + +on: workflow_call + +env: + DEFAULT_BRANCH: 'release' + #SPHINXOPTS: '-W --keep-going -T' + # ^-- If these SPHINXOPTS are enabled, then be strict about the builds and fail on any warnings + +jobs: + build-and-publish-docs: + name: Build and publish documentation + runs-on: ubuntu-latest + steps: + - name: Checkout active branch + uses: actions/checkout@v4 + with: + fetch-depth: 1 + lfs: true + - name: Install Python + uses: actions/setup-python@v4 + with: + python-version: '3.11' + cache: 'pip' # cache pip dependencies + - name: Install dependencies + run: | + pip install -r requirements-dev.txt + - name: Print debugging information + run: | + echo "github.ref:" ${{github.ref}} + echo "github.event_name:" ${{github.event_name}} + echo "github.head_ref:" ${{github.head_ref}} + echo "github.base_ref:" ${{github.base_ref}} + set -x + git rev-parse --abbrev-ref HEAD + git branch + git branch -a + git remote -v + python -V + pip list --not-required + pip list + + # Build documentation + - uses: sphinx-doc/github-problem-matcher@master + - name: Build documentation + run: | + cd docs + make html + + - name: Clone and cleanup gh-pages branch + run: | + set -x + git fetch + ( git branch gh-pages remotes/origin/gh-pages && git clone . --branch=gh-pages _gh-pages/ ) || mkdir _gh-pages + rm -rf _gh-pages/.git/ + mkdir -p _gh-pages/branch/ + + # Delete orphaned branch-folders: + # Go through each subfolder in _gh-pages/branch/ + # If it relates to an orphaned branch, delete it. + - name: Delete orphaned branch-folders + run: | + set -x + for brdir in `ls _gh-pages/branch/` ; do + brname=${brdir//--/\/} # replace '--' with '/' + if ! git show-ref remotes/origin/$brname ; then + echo "Removing $brdir" + rm -r _gh-pages/branch/$brdir/ + fi + done + + # Copy documentation to _gh-pages/ (if push happened on release branch) + - name: Copy documentation to _gh-pages/ + if: | + contains(github.ref, env.DEFAULT_BRANCH) + run: | + set -x + # Delete everything under _gh-pages/ that is from the + # primary branch deployment. Excludes the other branches + # _gh-pages/branch-* paths, and not including + # _gh-pages itself. + find _gh-pages/ -mindepth 1 ! -path '_gh-pages/branch*' -delete + rsync -a docs/build/html/ _gh-pages/ + + # Copy documentation to _gh-pages/branch/$brname (if push happened on any other branch) + # ('/' gets replaced by '--') + - name: Copy documentation to _gh-pages/branch/${{github.ref}} + if: | + !contains(github.ref, env.DEFAULT_BRANCH) + run: | + set -x + #brname=$(git rev-parse --abbrev-ref HEAD) + brname="${{github.ref}}" + brname="${brname##refs/heads/}" + brdir=${brname//\//--} # replace '/' with '--' + rm -rf _gh-pages/branch/${brdir} + rsync -a docs/build/html/ _gh-pages/branch/${brdir} + + # Add .nojekyll file + - name: Add .nojekyll file + run: touch _gh-pages/.nojekyll + + # Publish: Commit gh-pages branch and publish it to GitHub Pages + - name: Publish documentation + uses: peaceiris/actions-gh-pages@v3 + with: + publish_branch: gh-pages + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: _gh-pages/ + force_orphan: true diff --git a/.github/workflows/_build_package.yml b/.github/workflows/_build_package.yml new file mode 100644 index 0000000..7872bc7 --- /dev/null +++ b/.github/workflows/_build_package.yml @@ -0,0 +1,54 @@ +name: Build Package + +on: workflow_call + +jobs: + build: + name: Build source distribution + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 1 + lfs: true + - uses: actions/setup-python@v4 + with: + python-version: '3.11' + cache: 'pip' # cache pip dependencies + - name: Install build and twine + run: pip install build twine + - name: Run build + run: python -m build + - name: Run twine check + run: twine check --strict dist/* + - uses: actions/upload-artifact@v3 + with: + path: ./dist/*.tar.gz + + # build_wheels: + # name: Build wheels for ${{ matrix.platform }} + # needs: + # - black + # - ruff + # - pyright + # - test + # runs-on: ${{ matrix.platform }} + # strategy: + # matrix: + # platform: [ubuntu-latest, macos-latest, windows-latest] + # steps: + # - uses: actions/checkout@v4 + # with: + # fetch-depth: 1 + # lfs: true + # - uses: actions/setup-python@v4 + # with: + # python-version: '3.11' + # cache: 'pip' # cache pip dependencies + # - name: Install cibuildwheel + # run: python -m pip install cibuildwheel==2.16 + # - name: Build wheels + # run: python -m cibuildwheel --output-dir wheels + # - uses: actions/upload-artifact@v3 + # with: + # path: ./wheels/*.whl diff --git a/.github/workflows/_code_quality.yml b/.github/workflows/_code_quality.yml new file mode 100644 index 0000000..2ee8247 --- /dev/null +++ b/.github/workflows/_code_quality.yml @@ -0,0 +1,50 @@ +name: Code Quality + +on: workflow_call + +jobs: + black: + name: black + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: psf/black@stable + with: + options: '--check --diff' + src: '.' + jupyter: true + version: '==23.12' + + ruff: + runs-on: ubuntu-latest + name: ruff + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 + with: + python-version: '3.11' + cache: 'pip' # cache pip dependencies + - name: Install dependencies + run: pip install -r requirements.txt + - name: Install ruff + run: pip install ruff==0.1.8 + - name: Run ruff + run: ruff . + + pyright: + runs-on: ubuntu-latest + name: pyright + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 + with: + python-version: '3.11' + cache: 'pip' # cache pip dependencies + - name: Install dependencies + run: | + pip install -r requirements.txt + pip install pytest + - name: Install pyright + run: pip install pyright==1.1.338 + - name: Run pyright + run: pyright . diff --git a/.github/workflows/_merge_into_release.yml b/.github/workflows/_merge_into_release.yml new file mode 100644 index 0000000..cec3964 --- /dev/null +++ b/.github/workflows/_merge_into_release.yml @@ -0,0 +1,25 @@ +name: Merge into release + +on: + workflow_call: + secrets: + RELEASE_TOKEN: + required: true + +jobs: + merge_into_release: + name: Merge ${{ github.event.ref }} -> release branch + runs-on: ubuntu-latest + environment: release + steps: + - uses: actions/checkout@v4 + with: + # Fetch the whole history to prevent unrelated history errors + fetch-depth: 0 + # The branch you want to checkout (usually equal to `branchtomerge`) + # ref: ${{ github.event.ref }} + - uses: devmasx/merge-branch@v1.4.0 + with: + type: now + target_branch: release + github_token: ${{ secrets.RELEASE_TOKEN }} diff --git a/.github/workflows/_publish_package.yml b/.github/workflows/_publish_package.yml new file mode 100644 index 0000000..fe0b5b6 --- /dev/null +++ b/.github/workflows/_publish_package.yml @@ -0,0 +1,22 @@ +name: Publish Package to pypi + +on: + workflow_call: + secrets: + PYPI_API_TOKEN: + required: true + +jobs: + publish: + name: Publish package + runs-on: ubuntu-latest + environment: pypi + steps: + - uses: actions/download-artifact@v3 + with: + name: artifact + path: ./dist/ + - uses: pypa/gh-action-pypi-publish@v1.5.2 + with: + user: __token__ + password: ${{ secrets.PYPI_API_TOKEN }} diff --git a/.github/workflows/_publish_package_test.yml b/.github/workflows/_publish_package_test.yml new file mode 100644 index 0000000..971d7fd --- /dev/null +++ b/.github/workflows/_publish_package_test.yml @@ -0,0 +1,22 @@ +name: Publish Package to testpypi + +on: + workflow_call: + secrets: + TEST_PYPI_API_TOKEN: + required: true + +jobs: + publish: + name: Publish package + runs-on: ubuntu-latest + environment: pypi + steps: + - uses: actions/download-artifact@v3 + with: + name: artifact + path: ./dist/ + - uses: pypa/gh-action-pypi-publish@v1.5.2 + with: + user: __token__ + password: ${{ secrets.TEST_PYPI_API_TOKEN }} diff --git a/.github/workflows/_test.yml b/.github/workflows/_test.yml new file mode 100644 index 0000000..8b21b41 --- /dev/null +++ b/.github/workflows/_test.yml @@ -0,0 +1,35 @@ +name: Unit Tests + +on: workflow_call + +jobs: + test: + name: Test on ${{matrix.python.toxenv}}-${{matrix.platform.toxenv}} + runs-on: ${{ matrix.platform.runner }} + strategy: + matrix: + platform: + - runner: ubuntu-latest + toxenv: linux + - runner: windows-latest + toxenv: windows + python: + - version: '3.9' + toxenv: 'py39' + - version: '3.10' + toxenv: 'py310' + - version: '3.11' + toxenv: 'py311' + - version: '3.12' + toxenv: 'py312' + steps: + - uses: actions/checkout@v4 + - name: Install Python ${{ matrix.python.version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python.version }} + cache: 'pip' # cache pip dependencies + - name: Install tox + run: python -m pip install tox + - name: Run pytest + run: tox -e ${{matrix.python.toxenv}}-${{matrix.platform.toxenv}} diff --git a/.github/workflows/_test_future.yml b/.github/workflows/_test_future.yml new file mode 100644 index 0000000..5d07fee --- /dev/null +++ b/.github/workflows/_test_future.yml @@ -0,0 +1,31 @@ +name: Unit Tests (py312) +# Test also with Python 3.12 (experimental; workflow will not fail on error.) + +on: workflow_call + +jobs: + test312: + name: Test on ${{matrix.python.toxenv}}-${{matrix.platform.toxenv}} (experimental) + continue-on-error: true + runs-on: ${{ matrix.platform.runner }} + strategy: + matrix: + platform: + - runner: ubuntu-latest + toxenv: linux + - runner: windows-latest + toxenv: windows + python: + - version: '3.13.0a2' + toxenv: 'py313' + steps: + - uses: actions/checkout@v4 + - name: Install Python ${{ matrix.python.version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python.version }} + cache: 'pip' # cache pip dependencies + - name: Install tox + run: python -m pip install tox + - name: Run pytest + run: tox -e ${{matrix.python.toxenv}}-${{matrix.platform.toxenv}} diff --git a/.github/workflows/nightly_build.yml b/.github/workflows/nightly_build.yml new file mode 100644 index 0000000..28f6868 --- /dev/null +++ b/.github/workflows/nightly_build.yml @@ -0,0 +1,22 @@ +name: Nightly Build +run-name: Nightly Build (by @${{ github.actor }}) + +on: + schedule: + - cron: '30 5 * * *' + +jobs: + code_quality: + uses: ./.github/workflows/_code_quality.yml + test: + uses: ./.github/workflows/_test.yml + test_future: + uses: ./.github/workflows/_test_future.yml + build_package: + needs: + - test + uses: ./.github/workflows/_build_package.yml + build_and_publish_documentation: + needs: + - build_package + uses: ./.github/workflows/_build_and_publish_documentation.yml diff --git a/.github/workflows/publish_release.yml b/.github/workflows/publish_release.yml new file mode 100644 index 0000000..d7aa770 --- /dev/null +++ b/.github/workflows/publish_release.yml @@ -0,0 +1,27 @@ +name: Publish Release +run-name: Publish Release ${{ github.event.ref }} created by @${{ github.actor }} + +on: + push: + tags: + - v* + +jobs: + build_package: + uses: ./.github/workflows/_build_package.yml + # publish_package: + # needs: + # - build_package + # uses: ./.github/workflows/_publish_package.yml + # secrets: + # PYPI_API_TOKEN: ${{ secrets.PYPI_API_TOKEN }} + publish_package_test: + needs: + - build_package + uses: ./.github/workflows/_publish_package_test.yml + secrets: + TEST_PYPI_API_TOKEN: ${{ secrets.TEST_PYPI_API_TOKEN }} + merge_into_release: + uses: ./.github/workflows/_merge_into_release.yml + secrets: + RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }} diff --git a/.github/workflows/pull_request_to_main.yml b/.github/workflows/pull_request_to_main.yml new file mode 100644 index 0000000..2bff438 --- /dev/null +++ b/.github/workflows/pull_request_to_main.yml @@ -0,0 +1,28 @@ +name: Pull Request to main +run-name: Pull Request to main from ${{ github.event.pull_request.head.ref }} by @${{ github.actor }} + +on: + pull_request: + types: + - opened +# - synchronize + - reopened + - ready_for_review + - converted_to_draft + branches: + - main + +concurrency: + group: pr-${{ github.ref }}-1 + cancel-in-progress: true + +jobs: + code_quality: + uses: ./.github/workflows/_code_quality.yml + test: + uses: ./.github/workflows/_test.yml +# build_package: +# needs: +# - code_quality +# - test +# uses: ./.github/workflows/_build_package.yml diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml new file mode 100644 index 0000000..08debf2 --- /dev/null +++ b/.github/workflows/push.yml @@ -0,0 +1,18 @@ +name: Push to custom branches +run-name: Push to ${{ github.ref }} by @${{ github.actor }} + +on: + push: + branches-ignore: + - main + - release + +concurrency: + group: push-${{ github.ref }}-1 + cancel-in-progress: true + +jobs: + code_quality: + uses: ./.github/workflows/_code_quality.yml + test: + uses: ./.github/workflows/_test.yml diff --git a/.github/workflows/push_to_main.yml b/.github/workflows/push_to_main.yml new file mode 100644 index 0000000..735f70b --- /dev/null +++ b/.github/workflows/push_to_main.yml @@ -0,0 +1,26 @@ +name: Push to main +run-name: Push to main by @${{ github.actor }} + +on: + push: + branches: + - main + +concurrency: + group: push-${{ github.ref }}-1 + cancel-in-progress: true + +jobs: + code_quality: + uses: ./.github/workflows/_code_quality.yml + test: + uses: ./.github/workflows/_test.yml + build_package: + needs: + - code_quality + - test + uses: ./.github/workflows/_build_package.yml + build_and_publish_documentation: + needs: + - build_package + uses: ./.github/workflows/_build_and_publish_documentation.yml diff --git a/.github/workflows/push_to_release.yml b/.github/workflows/push_to_release.yml new file mode 100644 index 0000000..8880838 --- /dev/null +++ b/.github/workflows/push_to_release.yml @@ -0,0 +1,15 @@ +name: Push to release +run-name: Push to release by @${{ github.actor }} + +on: + push: + branches: + - release + +concurrency: + group: push-${{ github.ref }}-1 + cancel-in-progress: true + +jobs: + build_and_publish_documentation: + uses: ./.github/workflows/_build_and_publish_documentation.yml