diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index f4744d2..4efb8ee 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -46,7 +46,7 @@ on: required: false default: 'ubuntu-latest' type: string - save_artifact: + save_artifacts: description: Upload the built wheels as github artifacts required: false default: false @@ -213,7 +213,7 @@ jobs: CIBW_ARCHS: ${{ matrix.CIBW_ARCHS }} - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 if: | - needs.targets.outputs.upload_to_pypi == 'true' || inputs.upload_to_anaconda || inputs.save_artifact + needs.targets.outputs.upload_to_pypi == 'true' || inputs.upload_to_anaconda || inputs.save_artifacts with: name: "dist-${{ matrix.artifact-name }}" path: dist/* @@ -258,7 +258,7 @@ jobs: python-version: '3.12' - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 if: | - needs.targets.outputs.upload_to_pypi == 'true' || inputs.upload_to_anaconda || inputs.save_artifact + needs.targets.outputs.upload_to_pypi == 'true' || inputs.upload_to_anaconda || inputs.save_artifacts with: name: dist-sdist path: dist/* diff --git a/.github/workflows/publish_pure_python.yml b/.github/workflows/publish_pure_python.yml index 4547283..ed56f19 100644 --- a/.github/workflows/publish_pure_python.yml +++ b/.github/workflows/publish_pure_python.yml @@ -33,6 +33,11 @@ on: required: false default: 'ubuntu-latest' type: string + save_artifacts: + description: Upload the built dist(s) as github artifacts + required: false + default: false + type: boolean upload_to_pypi: description: A condition specifying whether to upload to PyPI required: false @@ -139,6 +144,11 @@ jobs: env: UPLOAD_TO_PYPI: ${{ inputs.upload_to_pypi }} UPLOAD_TAG: ${{ startsWith(inputs.upload_to_pypi, 'refs/tags/') && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || github.event_name == 'release' || github.event_name == 'create') && startsWith(github.ref, inputs.upload_to_pypi) }} + - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + if: ${{ inputs.save_artifacts }} + with: + name: "dist-publish-pure" + path: dist/* - uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0 name: Upload to PyPI if: ${{ steps.set-upload.outputs.upload_to_pypi == 'true' }} diff --git a/.github/workflows/test_publish.yml b/.github/workflows/test_publish.yml index 2e6ca0c..b6b2adc 100644 --- a/.github/workflows/test_publish.yml +++ b/.github/workflows/test_publish.yml @@ -24,6 +24,8 @@ jobs: release: uses: ./.github/workflows/publish.yml with: + save_artifacts: true + upload_to_pypi: false test_groups: test, concurrency test_extras: recommended test_command: pytest --pyargs test_package @@ -48,3 +50,21 @@ jobs: test_extras: recommended test_command: pytest --pyargs test_package targets: '' + + test-upload-external: + name: Use built dists and test upload + runs-on: ubuntu-latest + needs: [release] + steps: + - name: Download artifacts + uses: actions/download-artifact@v5 + with: + merge-multiple: true + pattern: dist-* + path: dist + + - run: ls -lha dist/ + + - name: Run upload (this will fail) + continue-on-error: true + uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/.github/workflows/test_publish_pure_python.yml b/.github/workflows/test_publish_pure_python.yml index 8b2da07..34326f5 100644 --- a/.github/workflows/test_publish_pure_python.yml +++ b/.github/workflows/test_publish_pure_python.yml @@ -25,6 +25,26 @@ jobs: setenv: uses: ./.github/workflows/publish_pure_python.yml with: + save_artifacts: true test_command: python -c "import os; assert os.getenv('CUSTOM_VAR') == 'custom value'" env: | CUSTOM_VAR: custom value + + + test-upload-external: + name: Use built dists and test upload + runs-on: ubuntu-latest + needs: [setenv] + steps: + - name: Download artifacts + uses: actions/download-artifact@v5 + with: + merge-multiple: true + pattern: dist-* + path: dist + + - run: ls -lha dist/ + + - name: Run upload (this will fail) + continue-on-error: true + uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/docs/source/index.rst b/docs/source/index.rst index 1cb1ffe..18f8b2a 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -1,3 +1,5 @@ +.. _oa-ghaw-index: + OpenAstronomy GitHub Actions Workflows ====================================== @@ -7,3 +9,4 @@ OpenAstronomy GitHub Actions Workflows tox publish publish_pure_python + trusted_publishing diff --git a/docs/source/publish.rst b/docs/source/publish.rst index 696a346..acf48e2 100644 --- a/docs/source/publish.rst +++ b/docs/source/publish.rst @@ -1,3 +1,5 @@ +.. _oa-ghaw-publish: + Build and publish a Python package ---------------------------------- @@ -173,8 +175,8 @@ repository_url The PyPI repository URL to use. Default is the main PyPI repository. -save_artifact -^^^^^^^^^^^^^ +save_artifacts +^^^^^^^^^^^^^^ Whether to save/upload the wheels as github artifacts. The default is to not save (unless ``upload_to_anaconda`` or ``upload_to_pypi`` is enabled). diff --git a/docs/source/publish_pure_python.rst b/docs/source/publish_pure_python.rst index 7147cff..b55a7f8 100644 --- a/docs/source/publish_pure_python.rst +++ b/docs/source/publish_pure_python.rst @@ -1,3 +1,5 @@ +.. _oa-ghaw-publish-pure: + Build and publish a pure Python package --------------------------------------- @@ -139,6 +141,11 @@ submodules Whether to checkout submodules. Default is ``true``. +save_artifacts +^^^^^^^^^^^^^^ + +Whether to save/upload the dist(s) as github artifacts. The default is to not save. + Secrets ~~~~~~~ diff --git a/docs/source/tox.rst b/docs/source/tox.rst index 52c925f..f6edcb0 100644 --- a/docs/source/tox.rst +++ b/docs/source/tox.rst @@ -1,3 +1,5 @@ +.. _oa-ghaw-tox: + Test a Python package using tox ------------------------------- diff --git a/docs/source/trusted_publishing.rst b/docs/source/trusted_publishing.rst new file mode 100644 index 0000000..478e8e2 --- /dev/null +++ b/docs/source/trusted_publishing.rst @@ -0,0 +1,61 @@ +.. _oa-ghaw-trusted-publishing: + +Using These Workflows with Trusted Publishing +--------------------------------------------- + +`Trusted Publishing `__ is a feature of PyPI which uses short lived tokens generated by a configured CI platform, in this case GitHub Actions. + +Currently, there is no direct support for using trusted publishing within a reuseable workflow, see `this issue `__ and links there-in. +To work around this limitation the :ref:`oa-ghaw-publish` and :ref:`oa-ghaw-publish-pure` workflows support uploading the built distributions as artifacts which can then be used by a subsequent job to upload to PyPI. + +Taking the example from :ref:`oa-ghaw-publish`, we add two new lines: + + +.. code-block:: yaml + :emphasize-lines: 5,6 + + jobs: + build: + uses: OpenAstronomy/github-actions-workflows/.github/workflows/publish.yml@v1 + with: + save_artifacts: true + upload_to_pypi: false + test_groups: test, concurrency + test_extras: recommended + test_command: pytest --pyargs test_package + targets: | + - linux + - cp3?-macosx_x86_64 + + +Setting ``upload_to_pypi: false`` means that the publish (or publish_pure) workflow will never try and upload to PyPI by itself. +The ``save_artifacts: true`` means that it will always run the ``actions/upload-artifact`` job so subsequent jobs in the workflow can use the dists. + +Next we have to configure a new job, which downloads the artifacts and then uses the `gh-action-pypi-publish `__ action to upload to PyPI. +As we are planning on using trusted publishing, we need to configure no options for this action. +We also add an if statement to the job so that it only runs on tags starting with a ``v``. + +.. code:: yaml + + jobs: + build: + ... + + upload: + if: startsWith(github.ref, 'refs/tags/v') + name: Use built dists and test upload + runs-on: ubuntu-latest + needs: [build] + steps: + - name: Download artifacts + uses: actions/download-artifact@v5 + with: + merge-multiple: true + pattern: dist-* + path: dist + + - name: Run upload + uses: pypa/gh-action-pypi-publish@release/v1 + + +You will also need to `Add a Trusted Publisher `__ to your PyPI project. diff --git a/tox.ini b/tox.ini index bfb2569..dd2e56e 100644 --- a/tox.ini +++ b/tox.ini @@ -63,3 +63,22 @@ commands = conda: python -c "import os, sys; assert os.path.exists(os.path.join(sys.prefix, 'conda-meta', 'history'))" conda: micromamba list pytest --pyargs test_package {posargs} + +[testenv:build_docs] +changedir = docs +description = Invoke sphinx-build to build the HTML docs +deps = + -r docs/requirements.txt +commands = + pip freeze --all --no-input + sphinx-build \ + -j auto \ + --color \ + -W \ + --keep-going \ + -b html \ + -d _build/.doctrees \ + ./source \ + _build/html \ + {posargs} + python -c 'import pathlib; print("Documentation available under file://\{0\}".format(pathlib.Path(r"{toxinidir}") / "docs" / "_build" / "index.html"))'