diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 980393de..d24ab9e8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -39,7 +39,7 @@ jobs: run: make requirements - name: Set up QEMU - uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # pin@v3.2.0 + uses: docker/setup-qemu-action@53851d14592bedcffcf25ea515637cff71ef929a # pin@v3.3.0 - name: Set up Docker Buildx uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # pin@v3.8.0 @@ -67,7 +67,7 @@ jobs: result-encoding: string - name: Build and push to DockerHub - uses: docker/build-push-action@48aba3b46d1b1fec4febb7c5d0c644b249a11355 # pin@v6.10.0 + uses: docker/build-push-action@ca877d9245402d1537745e0e356eab47c3520991 # pin@v6.13.0 with: context: . file: Dockerfile @@ -102,6 +102,6 @@ jobs: LINODE_CLI_VERSION: ${{ github.event.release.tag_name }} - name: Publish the release artifacts to PyPI - uses: pypa/gh-action-pypi-publish@67339c736fd9354cd4f8cb0b744f2b82a74b5c70 # pin@release/v1.12.3 + uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # pin@release/v1.12.4 with: password: ${{ secrets.PYPI_API_TOKEN }} diff --git a/.github/workflows/remote-release-trigger.yml b/.github/workflows/remote-release-trigger.yml index 6806ed09..db3b680b 100644 --- a/.github/workflows/remote-release-trigger.yml +++ b/.github/workflows/remote-release-trigger.yml @@ -66,7 +66,7 @@ jobs: commit_sha: ${{ steps.calculate_head_sha.outputs.commit_sha }} - name: Release - uses: softprops/action-gh-release@7b4da11513bf3f43f9999e90eabced41ab8bb048 # pin@v2.2.0 + uses: softprops/action-gh-release@c95fe1489396fe8a9eb87c0abf8aa5b2ef267fda # pin@v2.2.1 with: target_commitish: 'main' token: ${{ steps.generate_token.outputs.token }} diff --git a/linodecli/configuration/helpers.py b/linodecli/configuration/helpers.py index b9d502a0..cb0d5e9e 100644 --- a/linodecli/configuration/helpers.py +++ b/linodecli/configuration/helpers.py @@ -3,8 +3,10 @@ """ import configparser +import math import os import webbrowser +from functools import partial from typing import Any, Callable, List, Optional LEGACY_CONFIG_NAME = ".linode-cli" @@ -142,13 +144,14 @@ def _default_thing_input( exists = current_value is not None idx_offset = int(exists) + 1 + pad = partial(_pad_index, total=len(things) + idx_offset) # If there is a current value, users should have the option to clear it if exists: - print(" 1 - No Default") + print(f"{pad(1)} - No Default") for ind, thing in enumerate(things): - print(f" {ind + idx_offset} - {thing}") + print(f"{pad(ind + idx_offset)} - {thing}") print() while True: @@ -184,6 +187,16 @@ def _default_thing_input( return things[choice_idx] +def _pad_index(idx: int, total: int) -> str: + # NOTE: The implementation of this function could be less opaque if we're + # willing to say, "There will never be a case where total > X, because no + # one could examine and choose from that many options." + max_padding = math.floor(math.log10(total)) + 1 + num_spaces = max_padding - math.floor(math.log10(idx)) + + return " " * num_spaces + str(idx) + + def _default_text_input( ask: str, default: Optional[str] = None, diff --git a/pyproject.toml b/pyproject.toml index 8ce03bfa..8b1c35e1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,7 +22,7 @@ dependencies = [ dynamic = ["version"] [project.optional-dependencies] -obj = ["boto3"] +obj = ["boto3>=1.36.0"] dev = [ "pylint>=2.17.4", "pytest>=7.3.1", diff --git a/resolve_spec_url b/resolve_spec_url index 641beedc..60ae216f 100755 --- a/resolve_spec_url +++ b/resolve_spec_url @@ -39,5 +39,5 @@ if __name__ == "__main__": desired_version = get_latest_tag() print( - f"https://raw.githubusercontent.com/{LINODE_DOCS_REPO}/{desired_version}/openapi.yaml" + f"https://raw.githubusercontent.com/{LINODE_DOCS_REPO}/{desired_version}/openapi.json" ) diff --git a/tests/unit/test_configuration.py b/tests/unit/test_configuration.py index 2cd96f4c..474b083f 100644 --- a/tests/unit/test_configuration.py +++ b/tests/unit/test_configuration.py @@ -519,6 +519,47 @@ def test_default_thing_input_out_of_range(self, monkeypatch): assert result == "foo" + def test_default_thing_spacing(self, monkeypatch): + stdout_buf = io.StringIO() + monkeypatch.setattr("sys.stdin", io.StringIO("1\n")) + + with contextlib.redirect_stdout(stdout_buf): + _default_thing_input( + "foo\n", [*range(1, 10_001)], "prompt text", "error text" + ) + + output_lines = stdout_buf.getvalue().splitlines() + + assert output_lines[3] == " 1 - 1" + assert output_lines[11] == " 9 - 9" + assert output_lines[12] == " 10 - 10" + assert output_lines[101] == " 99 - 99" + assert output_lines[102] == " 100 - 100" + assert output_lines[1001] == " 999 - 999" + assert output_lines[1002] == " 1000 - 1000" + assert output_lines[10_001] == " 9999 - 9999" + assert output_lines[10_002] == " 10000 - 10000" + + def test_default_thing_spacing_with_current(self, monkeypatch): + stdout_buf = io.StringIO() + monkeypatch.setattr("sys.stdin", io.StringIO("1\n")) + + with contextlib.redirect_stdout(stdout_buf): + _default_thing_input( + "foo\n", + [*range(1, 10)], + "prompt text", + "error text", + current_value="foo", + ) + + output_lines = stdout_buf.getvalue().splitlines() + + print(output_lines) + assert output_lines[4] == " 2 - 1" + assert output_lines[11] == " 9 - 8" + assert output_lines[12] == " 10 - 9" + def test_default_text_input_optional(self, monkeypatch): # No value specified stdout_buf = io.StringIO()