Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
6 changes: 5 additions & 1 deletion .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
# Set update schedule for GitHub Actions
---
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"

- package-ecosystem: "uv"
directory: "/"
schedule:
interval: "weekly"
12 changes: 0 additions & 12 deletions .github/workflows/flake8.yml

This file was deleted.

28 changes: 3 additions & 25 deletions .github/workflows/publish_docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,33 +10,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6

- name: Setup Python
uses: actions/setup-python@v6
with:
python-version: "3.8"

- name: Upgrade pip
run: |
# install pip=>20.1 to use "pip cache dir"
python3 -m pip install --upgrade pip

- name: Get pip cache dir
id: pip-cache
run: echo "::set-output name=dir::$(pip cache dir)"

- name: Cache dependencies
uses: actions/cache@v5
- uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d
with:
path: ${{ steps.pip-cache.outputs.dir }}
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-

- name: Install dependencies
run: python3 -m pip install -r ./requirements-docs.txt
enable-cache: true

- run: mkdocs build
- run: uv run --frozen --group docs mkdocs build

- name: Deploy
uses: peaceiris/actions-gh-pages@v4
Expand Down
22 changes: 9 additions & 13 deletions .github/workflows/publish_pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v6
- uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d
with:
python-version: "3.x"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -U setuptools wheel twine
- name: Build and publish
enable-cache: true

- run: uv build

- name: Publish
env:
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
run: |
python setup.py sdist bdist_wheel
twine upload dist/*
UV_PUBLISH_USERNAME: ${{ secrets.PYPI_USERNAME }}
UV_PUBLISH_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
run: uv publish
36 changes: 21 additions & 15 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,38 +1,44 @@
name: Python package
name: Test

"on": [push]
"on": [push, pull_request]

jobs:
build:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d
with:
enable-cache: true
- run: uv run ruff check --output-format=github .
- run: uv run ruff format --check .

test:
runs-on: ubuntu-latest
strategy:
max-parallel: 4
fail-fast: false
matrix:
python-version:
- "3.9"
- "3.10"
- "3.11"
- "3.12"
- "3.13"
- "3.14"

steps:
- uses: actions/checkout@v6
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
- uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d
with:
enable-cache: true
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install tox tox-gh-actions
- name: Test with tox
run: tox

- run: uv run --frozen pytest --cov-report=xml

- name: Upload coverage to Codecov
if: matrix.python-version == '3.14'
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
file: ./coverage.xml
files: ./coverage.xml
flags: unittests
name: codecov-umbrella
yml: ./codecov.yml
15 changes: 8 additions & 7 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
.vscode
build
dist
*.egg-info
.eggs
__pycache__/
*.pyc
.coverage
.eggs
.ruff_cache
.tox
.venv
.vscode
__pycache__/
*.egg-info
*.pyc
build
coverage.xml
dist
site
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,30 @@

All notable changes to this project will be documented in this file.

## Unreleased

### Minor changes

- Python 3.10 is now the minimum supported version, tested up to Python 3.14.
- cloudscale-sdk updated to 0.7.0.
- Packaging moved from `setup.py` to `pyproject.toml`, the development
workflow uses `uv` and `ruff`.
- `--help` no longer requires an API token to be configured.

### Bug fixes

- Fixed `cloudscale server-group` not being available with Click 8.2 and newer,
where it was registered as `cloudscale server` and shadowed the server
commands.
- Fixed autocompletion instructions, which still used the Click 7 syntax.
- Fixed wrong column headers in table output when the listed resources did not
all provide the same fields.

### Other changes

- Running `cloudscale` without a command still shows the help, but exits with
the usage error code 2 as any other Click based CLI does.

## v1.5.0 (2025-06-24)

### Minor changes
Expand Down
5 changes: 0 additions & 5 deletions MANIFEST.in

This file was deleted.

38 changes: 27 additions & 11 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,17 +1,33 @@
clean:
rm -rf *.egg-info
rm -rf *.dist-info
rm -rf dist
rm -rf build
.PHONY: install lint format test build clean docs docs-serve release test-release

install:
uv sync

lint:
uv run ruff check .
uv run ruff format --check .

format:
uv run ruff check --fix .
uv run ruff format .

test:
uv run pytest

build: clean
python3 setup.py sdist bdist_wheel
uv build

test-release:
twine upload --repository testpypi dist/*
clean:
rm -rf dist build *.egg-info

release:
twine upload dist/*
docs-serve:
uv run --group docs mkdocs serve

docs:
mkdocs gh-deploy
uv run --group docs mkdocs gh-deploy

test-release: build
uv publish --index testpypi

release: build
uv publish
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Options:
-p, --profile TEXT Profile used in config file.
--debug Enables debug log output.
-o, --output [table|json] Output format. [default: table]
-v, --verbose Verbose output.
-h, --help Show this message and exit.

Commands:
Expand Down Expand Up @@ -58,5 +59,15 @@ To create a new release, follow these steps:
The branch should include the following:

- A single commit that updates the release.
- A version update in `cloudscale_cli/version.py`.
- A version update in `cloudscale_cli/__init__.py`.
- An updated changelog in `CHANGELOG.md`.
## Development

Requires Python 3.10 or newer and [uv](https://docs.astral.sh/uv/):

~~~shell
make install # create the virtualenv
make test # run the tests
make lint # run the linter and formatter checks
make format # apply the formatter
~~~
1 change: 1 addition & 0 deletions cloudscale_cli/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__version__ = "1.4.0"
49 changes: 34 additions & 15 deletions cloudscale_cli/cli.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
"""Entry point of the cloudscale.ch command line interface."""

import click

from .commands import OUTPUT_FORMATS, CloudscaleCommand
from . import __version__
from .command import CloudscaleCommand
from .commands.custom_image import custom_image
from .commands.flavor import flavor
from .commands.floating_ip import floating_ip
Expand All @@ -12,8 +15,14 @@
from .commands.server_group import server_group
from .commands.subnet import subnet
from .commands.volume import volume
from .util import OrderedGroup
from .version import __version__
from .output import OUTPUT_FORMATS


class OrderedGroup(click.Group):
"""A click group listing its commands in alphabetical order."""

def list_commands(self, ctx: click.Context) -> list[str]:
return sorted(self.commands)


@click.group(
Expand Down Expand Up @@ -43,7 +52,14 @@
"--verbose", "-v", envvar="CLOUDSCALE_VERBOSE", is_flag=True, help="Verbose output."
)
@click.pass_context
def cli(ctx, profile, api_token, debug, output, verbose):
def cli(
ctx: click.Context,
profile: str,
api_token: str,
debug: bool,
output: str,
verbose: bool,
) -> None:
ctx.obj = CloudscaleCommand(
api_token=api_token,
profile=profile,
Expand All @@ -53,14 +69,17 @@ def cli(ctx, profile, api_token, debug, output, verbose):
)


cli.add_command(custom_image, name='custom-image')
cli.add_command(flavor, name='flavor')
cli.add_command(floating_ip, name='floating-ip')
cli.add_command(image, name='image')
cli.add_command(network, name='network')
cli.add_command(objects_user, name='objects-user')
cli.add_command(region, name='region')
cli.add_command(server_group, name='server-group')
cli.add_command(server, name='server')
cli.add_command(subnet, name='subnet')
cli.add_command(volume, name='volume')
for command in (
custom_image,
flavor,
floating_ip,
image,
network,
objects_user,
region,
server,
server_group,
subnet,
volume,
):
cli.add_command(command)
Loading
Loading