Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
GitHub action to setup poetry
actions/setup-python does the hard work for us, but we make use of
actions/cache to avoid having to re-install poetry and the project
unless the poetry version we're using has changed, or the hash of
the lockfile has changed.

After using this action, subsequent job steps can use `poetry run foo
[...]` to run `foo [...]` in the virtual environment.
  • Loading branch information
David Robertson committed Feb 2, 2022
commit 43e636b802e607915d06d7eda4feed082b0280f0
83 changes: 83 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
name: Setup Python and Poetry
description: Setup Python and Poetry. Cribbed from snok/install-poetry.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to carry any licensing info across, and/or perhaps link to it in a hypothetical README?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Cribbed" is maybe the wrong word. I looked to see how that action worked, but in the end decided I wanted different behaviour and wrote most of the yaml from scratch. snok's action was very useful for understanding what is/was going on with poetry though.

I'll acknowledge this and mark this as MIT licensed to match snok/install-poetry. I know we normally use Apache 2, but given that this is CI config rather than a core software component I think that's fine.

inputs:
python-version:
description: Python version to pass to actions/setup-python@v2.
required: false
default: "3.x"
poetry-version:
description: Poetry version to install via pip.
required: false
default: "1.1.12"
debug:
description: If set to the string 'true', dump the state of the virtual env after setup.
required: false
default: "false"
runs:
using: composite
steps:
- name: Setup Python
id: setup-python
uses: actions/setup-python@v2
with:
python-version: ${{ inputs.python-version }}

- name: Check for poetry lock
run: "test -f poetry.lock || (echo No lock file! && false)"
shell: bash
Comment on lines +21 to +23
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the poetry lock file a necessary requirement? What about for libraries?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm proposing that we only use this action for projects with a lockfile.

The conventional wisdom for libraries is not to commit a lockfile. That means each CI run would end formally resolving dependencies, which can be sluggish. See for instance this older attempt in signedjson: poetry install --no-interaction took 22 seconds.

I suspect that building a wheel and installing it in editable mode with pip would be quicker. But more generally I've just kicked the "what do we do about libraries" can down the road.


# Install poetry. It takes ~10seconds for a clean pip install, most of which is
# the installation rather than the downloading. So instead, we cache the user-base
# directory (~/.local). For this to be safe:
# - we must not write to `.local` as part of the CI
# - we must not install anything with the system `pip` other than poetry.
# Based on the writeup at:
# https://github.com/snok/install-poetry/blob/main/README.md#caching-the-poetry-installation
- name: Locate user site
id: site-user-base
run: echo "::set-output name=dir::$(python -m site --user-base)"
shell: bash

- name: Restore poetry installation
id: poetry-install-cache
uses: actions/cache@v2
with:
path: ${{ steps.site-user-base.outputs.dir }}
key: poetry-install-cache-${{ steps.setup-python.outputs.python-version }}-${{ inputs.poetry-version }}

- name: Install poetry from scratch
if: "${{ steps.poetry-install-cache.outputs.cache-hit != 'true' }}"
run: python -m pip install --user poetry==${{ inputs.poetry-version }}
shell: bash

# Poetry manages a virtualenv for us. We're going to cache that too.
# Again, we're following snok/install-poetry's README.
- name: Locate poetry venv
id: poetry-venvs
run: echo "::set-output name=dir::$(python -m poetry config virtualenvs.path)"
shell: bash

- name: Restore poetry venv
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling this 'Restore' is a little bit confusing because I think this is also saving to the cache afterwards?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In one of the final steps, yes (but only if there wasn't a cache hit in the first place)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about Restore/cache foo bar?

id: poetry-venv-cache
uses: actions/cache@v2
with:
path: ${{ steps.poetry-venvs.outputs.dir }}
key: poetry-venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('**/poetry.lock') }}

- name: Install dependencies
if: "${{ steps.poetry-venv-cache.outputs.cache-hit != 'true' }}"
run: poetry install --no-interaction --no-root
shell: bash

# (Not sure if this is needed if there's a cache hit?)
- name: Install project
run: poetry install --no-interaction
shell: bash

# For debugging---let's just check what we're working with.
- name: Dump virtual environment
if: "${{ inputs.debug == 'true' }}"
run: |
poetry env info
poetry show
shell: bash
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this output is only small I would be tempted to emit it unconditionally — when CI fails it's a nuisance to have to restart it all up in debug mode (?) to find out why, when it could just have been in the logs.