diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 608fa6fad..e57378c2f 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -1,4 +1,4 @@ -# Build the documentation and deploy to GitHub Pages using GitHub Actions. +# Build the documentation to check that it works without errors. # # NOTE: Pin actions to a specific commit to avoid having the authentication # token stolen if the Action is compromised. See the comments and links here: @@ -6,17 +6,11 @@ # name: documentation -# Only build PRs, the main branch, and releases. Pushes to branches will only -# be built when a PR is opened. This avoids duplicated buids in PRs comming -# from branches in the origin repository (1 for PR and 1 for push). on: pull_request: push: branches: - main - release: - types: - - published permissions: {} @@ -77,11 +71,7 @@ jobs: run: conda list - name: Build source and wheel distributions - run: | - make build - echo "" - echo "Generated files:" - ls -lh dist/ + run: make build - name: Install the package run: python -m pip install --no-deps dist/*.whl @@ -98,97 +88,3 @@ jobs: sleep 3 # Build the docs make -C doc clean all - - # Store the docs as a build artifact so we can deploy it later - - name: Upload HTML documentation as an artifact - if: success() - uses: actions/upload-artifact@v7 - with: - name: docs-${{ github.sha }} - path: doc/_build/html - - ############################################################################# - # Publish the documentation to gh-pages - publish: - runs-on: ubuntu-latest - needs: build - permissions: - contents: write - if: github.event_name == 'release' || github.event_name == 'push' - - steps: - - name: Checkout - uses: actions/checkout@v6 - with: - # The GitHub token is preserved by default but this job doesn't need - # to be able to push to GitHub. - persist-credentials: false - - # Fetch the built docs from the "build" job - - name: Download HTML documentation artifact - uses: actions/download-artifact@v8 - with: - name: docs-${{ github.sha }} - path: doc/_build/html - - - name: Checkout the gh-pages branch in a separate folder - uses: actions/checkout@v6 - with: - ref: gh-pages - # Checkout to this folder instead of the current one - path: deploy - # Download the entire history - fetch-depth: 0 - # We need to explicitly preserve the credentials for the GitHub token - # on this branch so we can push to it. - persist-credentials: true - - - name: Push the built HTML to gh-pages - run: | - # Detect if this is a release or from the main branch - if [[ "${{ github.event_name }}" == "release" ]]; then - # Get the tag name without the "refs/tags/" part - version="${GITHUB_REF#refs/*/}" - else - version=dev - fi - echo "Deploying version: $version" - # Make the new commit message. Needs to happen before cd into deploy - # to get the right commit hash. - message="Deploy $version from $(git rev-parse --short HEAD)" - cd deploy || exit 1 - # Need to have this file so that Github doesn't try to run Jekyll - touch .nojekyll - # Delete all the files and replace with our new set - echo -e "\nRemoving old files from previous builds of ${version}:" - rm -rvf "${version}" - echo -e "\nCopying HTML files to ${version}:" - cp -Rvf ../doc/_build/html/ "${version}/" - # If this is a new release, update the link from /latest to it - if [[ "${version}" != "dev" ]]; then - echo -e "\nSetup link from ${version} to 'latest'." - rm -f latest - ln -sf "${version}" latest - fi - # Stage the commit - git add -A . - echo -e "\nChanges to be applied:" - git status - # Configure git to be the GitHub Actions account - git config user.email "github-actions[bot]@users.noreply.github.com" - git config user.name "github-actions[bot]" - # If this is a dev build and the last commit was from a dev build - # (detect if "dev" was in the previous commit message), reuse the - # same commit - if [[ "${version}" == "dev" && $(git log -1 --format='%s') == *"dev"* ]]; then - echo -e "\nAmending last commit:" - git commit --amend --reset-author -m "$message" - else - echo -e "\nMaking a new commit:" - git commit -m "$message" - fi - # Make the push quiet just in case there is anything that could leak - # sensitive information. - echo -e "\nPushing changes to gh-pages." - { git push -fq origin gh-pages >/dev/null; } 2>&1 - echo -e "\nFinished uploading generated files." diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 000000000..20219d6c0 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,194 @@ +# Build and publish packages to PyPI and documentation to GitHub Pages +# +# NOTE: Pin actions to a specific commit to avoid having the authentication +# token stolen if the Action is compromised. See the comments and links here: +# https://github.com/pypa/gh-action-pypi-publish/issues/27 +# +name: publish + +# Only pushed to the main branch and releases. +on: + push: + branches: + - main + release: + types: + - published + +permissions: {} + +# Use bash by default in all jobs +defaults: + run: + # The -l {0} is necessary for conda environments to be activated + # But this breaks on MacOS if using actions/setup-python: + # https://github.com/actions/setup-python/issues/132 + # -e makes sure builds fail if any command fails + shell: bash -e -o pipefail -l {0} + +jobs: + + deploy: + runs-on: ubuntu-latest + permissions: + # Grant write permissions so that we can push to gh-pages + contents: write + # This permission allows trusted publishing to PyPI (without an API token) + id-token: write + environment: pypi + env: + REQUIREMENTS: env/requirements-docs.txt env/requirements-build.txt + ENSAIO_DATA_FROM_GITHUB: true + PYTHON: "3.12" + + steps: + # Checks-out your repository under $GITHUB_WORKSPACE + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + # Need to fetch more than the last commit so that setuptools-scm can + # create the correct version string. If the number of commits since + # the last release is greater than this, the version still be wrong. + # Increase if necessary. + fetch-depth: 100 + # The GitHub token is preserved by default but this job doesn't need + # to be able to push to GitHub. + persist-credentials: false + + # Need the tags so that setuptools-scm can form a valid version number + - name: Fetch git tags + run: git fetch origin 'refs/tags/*:refs/tags/*' + + - name: Setup Miniforge + uses: conda-incubator/setup-miniconda@fc2d68f6413eb2d87b895e92f8584b5b94a10167 + with: + python-version: ${{ env.PYTHON }} + miniforge-version: latest + channels: conda-forge + conda-remove-defaults: "true" + activate-environment: harmonica-docs + environment-file: .github/environment.yml + + - name: List installed packages + run: conda list + + - name: Don't use local version numbers for PyPI uploads + run: | + # Change setuptools-scm local_scheme to "no-local-version" so the + # local part of the version isn't included, making the version string + # compatible with Test PyPI. + sed --in-place "s/node-and-date/no-local-version/g" pyproject.toml + + - name: Build source and wheel distributions + run: | + make build + echo "" + echo "Generated files:" + ls -lh dist/ + + - name: Check the archives + run: twine check dist/* + + - name: Install the package + run: python -m pip install --no-deps dist/*.whl + + - name: Build the documentation + run: | + # Install xvfb and run some commands to allow pyvista to run on + # a headless system. + sudo apt-get install xvfb + export DISPLAY=:99.0 + export PYVISTA_OFF_SCREEN=true + export PYVISTA_USE_IPYVTK=true + Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & + sleep 3 + # Build the docs + make -C doc clean all + + - name: Checkout the gh-pages branch in a separate folder + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + ref: gh-pages + # Checkout to this folder instead of the current one + path: deploy + # Download the entire history + fetch-depth: 0 + # We need to explicitly preserve the credentials for the GitHub token + # on this branch so we can push to it. + persist-credentials: true + + - name: Push the built HTML to gh-pages + if: success() + run: | + # Detect if this is a release or from the main branch + if [[ "${{ github.event_name }}" == "release" ]]; then + # Get the tag name without the "refs/tags/" part + version="${GITHUB_REF#refs/*/}" + else + version=dev + fi + echo "Deploying version: $version" + + # Make the new commit message. Needs to happen before cd into deploy + # to get the right commit hash. + message="Deploy $version from $(git rev-parse --short HEAD)" + + cd deploy || exit 1 + + # Need to have this file so that Github doesn't try to run Jekyll + touch .nojekyll + + # Delete all the files and replace with our new set + echo -e "\nRemoving old files from previous builds of ${version}:" + rm -rvf "${version}" + echo -e "\nCopying HTML files to ${version}:" + cp -Rvf ../doc/_build/html/ "${version}/" + + # If this is a new release, update the link from /latest to it + if [[ "${version}" != "dev" ]]; then + echo -e "\nSetup link from ${version} to 'latest'." + rm -f latest + ln -sf "${version}" latest + fi + + # Stage the commit + git add -A . + echo -e "\nChanges to be applied:" + git status + + # Configure git to be the GitHub Actions account + git config user.email "github-actions[bot]@users.noreply.github.com" + git config user.name "github-actions[bot]" + + # If this is a dev build and the last commit was from a dev build + # (detect if "dev" was in the previous commit message), reuse the + # same commit + if [[ "${version}" == "dev" && $(git log -1 --format='%s') == *"dev"* ]]; then + echo -e "\nAmending last commit:" + git commit --amend --reset-author -m "$message" + else + echo -e "\nMaking a new commit:" + git commit -m "$message" + fi + + # Make the push quiet just in case there is anything that could leak + # sensitive information. + echo -e "\nPushing changes to gh-pages." + { git push -fq origin gh-pages > /dev/null; } 2>&1 + + echo -e "\nFinished uploading generated files." + + - name: Publish to Test PyPI + # Only publish to TestPyPI when a PR is merged (pushed to main) + if: success() && github.event_name == 'push' + uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b + with: + repository-url: https://test.pypi.org/legacy/ + # Allow existing releases on test PyPI without errors. + # NOT TO BE USED in PyPI! + skip-existing: true + + - name: Publish to PyPI + # Only publish to PyPI when a release triggers the build + if: success() && github.event_name == 'release' + uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml deleted file mode 100644 index 42b4c9d6a..000000000 --- a/.github/workflows/pypi.yml +++ /dev/null @@ -1,128 +0,0 @@ -# Publish archives to PyPI and TestPyPI using GitHub Actions. -# -# NOTE: Pin actions to a specific commit to avoid having the authentication -# token stolen if the Action is compromised. See the comments and links here: -# https://github.com/pypa/gh-action-pypi-publish/issues/27 -# -name: pypi - -# Runs on these events but only publish on pushes to main (to test pypi) and -# releases -on: - pull_request: - push: - branches: - - main - release: - types: - - published - -permissions: {} - -# Use bash by default in all jobs -defaults: - run: - shell: bash - -jobs: - ############################################################################# - # Build and check source and wheel distributions - build: - runs-on: ubuntu-latest - - steps: - # Checks-out your repository under $GITHUB_WORKSPACE - - name: Checkout - uses: actions/checkout@v6 - with: - # Need to fetch more than the last commit so that setuptools_scm can - # create the correct version string. If the number of commits since - # the last release is greater than this, the version will still be - # wrong. Increase if necessary. - fetch-depth: 200 - # The GitHub token is preserved by default but this job doesn't need - # to be able to push to GitHub. - persist-credentials: false - - # Need the tags so that setuptools-scm can form a valid version number - - name: Fetch git tags - run: git fetch origin 'refs/tags/*:refs/tags/*' - - - name: Setup Python - uses: actions/setup-python@v6 - with: - python-version: "3.12" - - - name: Install requirements - run: python -m pip install -r env/requirements-build.txt - - - name: List installed packages - run: python -m pip freeze - - - name: Don't use local version numbers for TestPyPI uploads - if: github.event_name != 'release' - run: | - # Change setuptools-scm local_scheme to "no-local-version" so the - # local part of the version isn't included, making the version string - # compatible with Test PyPI. - sed --in-place "s/node-and-date/no-local-version/g" pyproject.toml - - - name: Build source and wheel distributions - run: | - make build - echo "" - echo "Generated files:" - ls -lh dist/ - - - name: Check the archives - run: twine check dist/* - - # Store the archives as a build artifact so we can deploy them later - - name: Upload archives as artifacts - # Only if not a pull request - if: success() && github.event_name != 'pull_request' - uses: actions/upload-artifact@v7 - with: - name: pypi-${{ github.sha }} - path: dist - - ############################################################################# - # Publish built wheels and source archives to PyPI and test PyPI - publish: - runs-on: ubuntu-latest - needs: build - # Only publish from the origin repository, not forks - if: github.repository_owner == 'fatiando' && github.event_name != 'pull_request' - environment: pypi - permissions: - # This permission allows trusted publishing to PyPI (without an API token) - id-token: write - - steps: - - name: Checkout - uses: actions/checkout@v6 - with: - # The GitHub token is preserved by default but this job doesn't need - # to be able to push to GitHub. - persist-credentials: false - - - name: Download built source and wheel packages - uses: actions/download-artifact@v8 - with: - name: pypi-${{ github.sha }} - path: dist - - - name: Publish to Test PyPI - # Only publish to TestPyPI when a PR is merged (pushed to main) - if: success() && github.event_name == 'push' - uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b - with: - repository_url: https://test.pypi.org/legacy/ - # Allow existing releases on test PyPI without errors. - # NOT TO BE USED in PyPI! - skip_existing: true - - - name: Publish to PyPI - # Only publish to PyPI when a release triggers the build - if: success() && github.event_name == 'release' - uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7b23be103..fb6da34a9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,24 +6,22 @@ # name: test -# Only build PRs, the main branch, and releases. Pushes to branches will only -# be built when a PR is opened. This avoids duplicated buids in PRs comming -# from branches in the origin repository (1 for PR and 1 for push). on: pull_request: push: branches: - main - release: - types: - - published permissions: {} # Use bash by default in all jobs defaults: run: - shell: bash + # The -l {0} is necessary for conda environments to be activated + # But this breaks on MacOS if using actions/setup-python: + # https://github.com/actions/setup-python/issues/132 + # -e makes sure builds fail if any command fails + shell: bash -e -o pipefail -l {0} jobs: ############################################################################# @@ -51,10 +49,6 @@ jobs: python: "3.13" - dependencies: optional python: "3.13" - # Include tests on macos (x86) with oldest dependencies - - os: macos-15-intel - dependencies: oldest - python: "3.10" env: REQUIREMENTS: env/requirements-build.txt env/requirements-tests.txt @@ -124,7 +118,13 @@ jobs: - name: List installed packages run: python -m pip freeze - # Needs to be editable for coverage reporting to work + - name: Build source and wheel distributions + run: make build + + - name: Check the archives + run: twine check dist/* + + # Do this instead of using the wheel so we can get proper coverage reports - name: Install the package in editable mode run: python -m pip install --no-deps --editable .