From 524b7e7b95dcd6adc311e74dd7f0e6da8a3cce58 Mon Sep 17 00:00:00 2001 From: Aurelio Jargas Date: Tue, 18 Jun 2024 17:09:39 +0200 Subject: [PATCH] Add ensure-poetry role Poetry (https://python-poetry.org) is not declared as a dependency for a Python project, it must be available somehow in the system. This role installs it if missing. - Latest version is installed, unless `ensure_poetry_version` is informed. - The installed executable path is set as the `poetry_executable` fact. - The `/usr/local/bin/poetry` symlink can also be created if `ensure_poetry_global_symlink: true`. This new role is basically a copy of the `ensure-nox` role with the symlink creation snippet taken from the `ensure-tox` role. The commit adding `ensure-nox` (77b1b24) has been taken as an example of the necessary changes when adding a new role. Change-Id: I5592d38d415a9d74055348406653b69f110541ae --- doc/source/python-roles.rst | 1 + roles/ensure-poetry/README.rst | 42 +++++++++++++++ roles/ensure-poetry/defaults/main.yaml | 4 ++ roles/ensure-poetry/tasks/main.yaml | 44 +++++++++++++++ test-playbooks/ensure-poetry.yaml | 35 ++++++++++++ zuul-tests.d/python-jobs.yaml | 75 ++++++++++++++++++++++++++ 6 files changed, 201 insertions(+) create mode 100644 roles/ensure-poetry/README.rst create mode 100644 roles/ensure-poetry/defaults/main.yaml create mode 100644 roles/ensure-poetry/tasks/main.yaml create mode 100644 test-playbooks/ensure-poetry.yaml diff --git a/doc/source/python-roles.rst b/doc/source/python-roles.rst index b99790396..dc6303110 100644 --- a/doc/source/python-roles.rst +++ b/doc/source/python-roles.rst @@ -7,6 +7,7 @@ Python Roles .. zuul:autorole:: ensure-if-python .. zuul:autorole:: ensure-nox .. zuul:autorole:: ensure-pip +.. zuul:autorole:: ensure-poetry .. zuul:autorole:: ensure-python .. zuul:autorole:: ensure-sphinx .. zuul:autorole:: ensure-tox diff --git a/roles/ensure-poetry/README.rst b/roles/ensure-poetry/README.rst new file mode 100644 index 000000000..aab79ea2b --- /dev/null +++ b/roles/ensure-poetry/README.rst @@ -0,0 +1,42 @@ +Ensure Poetry is installed + +Look for ``poetry``, and if not found, install it via ``pip`` into a +virtual environment for the current user. + +**Role Variables** + +.. zuul:rolevar:: ensure_poetry_version + :default: '' + + Version specifier to select the version of Poetry. The default is the + latest version. + +.. zuul:rolevar:: ensure_poetry_venv_path + :default: {{ ansible_user_dir }}/.local/poetry + + Directory for the Python venv where Poetry will be installed. + +.. zuul:rolevar:: ensure_poetry_global_symlink + :default: False + + Install a symlink to the poetry executable into ``/usr/local/bin/poetry``. + This can be useful when scripts need to be run that expect to find + Poetry in a more standard location and plumbing through the value + of ``ensure_poetry_executable`` would be onerous. + + Setting this requires root access, so should only be done in + circumstances where root access is available. + +**Output Variables** + +.. zuul:rolevar:: ensure_poetry_executable + :default: poetry + + After running this role, ``ensure_poetry_executable`` will be set as the path + to a valid ``poetry``. + + At role runtime, look for an existing ``poetry`` at this specific + path. Note the default (``poetry``) effectively means to find poetry in + the current ``$PATH``. For example, if your base image + pre-installs poetry in an out-of-path environment, set this so the + role does not attempt to install the user version. diff --git a/roles/ensure-poetry/defaults/main.yaml b/roles/ensure-poetry/defaults/main.yaml new file mode 100644 index 000000000..9ce9c23f4 --- /dev/null +++ b/roles/ensure-poetry/defaults/main.yaml @@ -0,0 +1,4 @@ +ensure_poetry_global_symlink: false +ensure_poetry_version: "" +ensure_poetry_executable: poetry +ensure_poetry_venv_path: "{{ ansible_user_dir }}/.local/poetry" diff --git a/roles/ensure-poetry/tasks/main.yaml b/roles/ensure-poetry/tasks/main.yaml new file mode 100644 index 000000000..011104910 --- /dev/null +++ b/roles/ensure-poetry/tasks/main.yaml @@ -0,0 +1,44 @@ +- name: Install pip + include_role: + name: ensure-pip + +- name: Check if poetry is installed + shell: | + command -v {{ ensure_poetry_executable }} {{ ensure_poetry_venv_path }}/bin/poetry || exit 1 + args: + executable: /bin/bash + register: poetry_preinstalled + failed_when: false + +- name: Export preinstalled ensure_poetry_executable + set_fact: + ensure_poetry_executable: "{{ poetry_preinstalled.stdout_lines[0] }}" + cacheable: true + when: poetry_preinstalled.rc == 0 + +- name: Install poetry to local env + when: poetry_preinstalled.rc != 0 + block: + - name: Create local venv + command: "{{ ensure_pip_virtualenv_command }} {{ ensure_poetry_venv_path }}" + + - name: Install poetry to local venv + command: "{{ ensure_poetry_venv_path }}/bin/pip install poetry{{ ensure_poetry_version }}" + + - name: Export installed ensure_poetry_executable path + set_fact: + ensure_poetry_executable: "{{ ensure_poetry_venv_path }}/bin/poetry" + cacheable: true + +- name: Output poetry version + command: "{{ ensure_poetry_executable }} --version" + +- name: Make global symlink + when: + - ensure_poetry_global_symlink + - ensure_poetry_executable != '/usr/local/bin/poetry' + file: + state: link + src: "{{ ensure_poetry_executable }}" + dest: /usr/local/bin/poetry + become: yes diff --git a/test-playbooks/ensure-poetry.yaml b/test-playbooks/ensure-poetry.yaml new file mode 100644 index 000000000..9cc0246fb --- /dev/null +++ b/test-playbooks/ensure-poetry.yaml @@ -0,0 +1,35 @@ +- hosts: all + name: Test ensure-poetry installs into user environment + tasks: + - name: Verify poetry is not installed + command: "poetry --version" + register: result + failed_when: result.rc == 0 + - name: Run ensure-poetry with poetry not installed + include_role: + name: ensure-poetry + - name: Verify ensure_poetry_executable is set + assert: + that: + - ensure_poetry_executable == ansible_user_dir + '/.local/poetry/bin/poetry' + - name: Verify poetry is installed + command: "{{ ensure_poetry_executable }} --version" + register: result + failed_when: result.rc != 0 + +- hosts: all + name: Test ensure-poetry when ensure_poetry_executable is set to an already installed poetry + tasks: + - name: Create a virtualenv + command: '{{ ensure_pip_virtualenv_command }} {{ ansible_user_dir }}/poetry-venv' + - name: Install poetry to local venv + command: '{{ ansible_user_dir }}/poetry-venv/bin/pip install poetry' + - name: Run ensure-poetry pointing to an already installed poetry + include_role: + name: ensure-poetry + vars: + ensure_poetry_executable: "{{ ansible_user_dir }}/poetry-venv/bin/poetry" + - name: Verify ensure_poetry_executable is set to the virtualenv poetry + assert: + that: + - ensure_poetry_executable == ansible_user_dir + '/poetry-venv/bin/poetry' diff --git a/zuul-tests.d/python-jobs.yaml b/zuul-tests.d/python-jobs.yaml index 5109a11bf..06847127f 100644 --- a/zuul-tests.d/python-jobs.yaml +++ b/zuul-tests.d/python-jobs.yaml @@ -144,6 +144,75 @@ nodeset: nodes: [] +- job: + name: zuul-jobs-test-ensure-poetry + description: Test the ensure-poetry role + files: + - roles/ensure-poetry/.* + - test-playbooks/ensure-poetry.yaml + run: test-playbooks/ensure-poetry.yaml + tags: all-platforms + +- job: + name: zuul-jobs-test-ensure-poetry-centos-9-stream + description: Test the ensure-poetry role on centos-9-stream + parent: zuul-jobs-test-ensure-poetry + tags: auto-generated + nodeset: + nodes: + - name: centos-9-stream + label: centos-9-stream + +- job: + name: zuul-jobs-test-ensure-poetry-debian-bookworm + description: Test the ensure-poetry role on debian-bookworm + parent: zuul-jobs-test-ensure-poetry + tags: auto-generated + nodeset: + nodes: + - name: debian-bookworm + label: debian-bookworm + +- job: + name: zuul-jobs-test-ensure-poetry-debian-bullseye + description: Test the ensure-poetry role on debian-bullseye + parent: zuul-jobs-test-ensure-poetry + tags: auto-generated + nodeset: + nodes: + - name: debian-bullseye + label: debian-bullseye + +- job: + name: zuul-jobs-test-ensure-poetry-ubuntu-focal + description: Test the ensure-poetry role on ubuntu-focal + parent: zuul-jobs-test-ensure-poetry + tags: auto-generated + nodeset: + nodes: + - name: ubuntu-focal + label: ubuntu-focal + +- job: + name: zuul-jobs-test-ensure-poetry-ubuntu-jammy + description: Test the ensure-poetry role on ubuntu-jammy + parent: zuul-jobs-test-ensure-poetry + tags: auto-generated + nodeset: + nodes: + - name: ubuntu-jammy + label: ubuntu-jammy + +- job: + name: zuul-jobs-test-ensure-poetry-ubuntu-noble + description: Test the ensure-poetry role on ubuntu-noble + parent: zuul-jobs-test-ensure-poetry + tags: auto-generated + nodeset: + nodes: + - name: ubuntu-noble + label: ubuntu-noble + - job: name: zuul-jobs-test-ensure-sphinx description: Test the ensure-sphinx role @@ -420,6 +489,12 @@ - zuul-jobs-test-ensure-pip-ubuntu-jammy - zuul-jobs-test-ensure-pip-ubuntu-noble - zuul-jobs-test-ensure-pip-localhost + - zuul-jobs-test-ensure-poetry-centos-9-stream + - zuul-jobs-test-ensure-poetry-debian-bookworm + - zuul-jobs-test-ensure-poetry-debian-bullseye + - zuul-jobs-test-ensure-poetry-ubuntu-focal + - zuul-jobs-test-ensure-poetry-ubuntu-jammy + - zuul-jobs-test-ensure-poetry-ubuntu-noble - zuul-jobs-test-ensure-sphinx - zuul-jobs-test-ensure-tox-centos-9-stream - zuul-jobs-test-ensure-tox-debian-bookworm