From a9d823d4fbd311170a49c8e63bb2daf020ba35a1 Mon Sep 17 00:00:00 2001 From: Riccardo Schirone Date: Fri, 13 Mar 2026 14:09:26 +0100 Subject: [PATCH 1/2] Update default Ubuntu image from 25.04 to 25.10 Co-Authored-By: Claude Opus 4.6 --- dropkit/api.py | 2 +- dropkit/config.py | 2 +- dropkit/main.py | 4 ++-- tests/test_config.py | 18 +++++++++--------- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/dropkit/api.py b/dropkit/api.py index fdb1a6a..47e09b3 100644 --- a/dropkit/api.py +++ b/dropkit/api.py @@ -329,7 +329,7 @@ def create_droplet( name: Droplet name region: Region slug (e.g., 'nyc3') size: Size slug (e.g., 's-2vcpu-4gb') - image: Image slug (e.g., 'ubuntu-25-04-x64') + image: Image slug (e.g., 'ubuntu-25-10-x64') user_data: Cloud-init user data tags: List of tags to apply ssh_keys: List of SSH key IDs for root access (optional) diff --git a/dropkit/config.py b/dropkit/config.py index 8916f29..df87d6e 100644 --- a/dropkit/config.py +++ b/dropkit/config.py @@ -298,7 +298,7 @@ def create_default_config( username: str, # noqa: ARG002 - kept for API compatibility, username derived from DO API region: str = "nyc3", size: str = "s-2vcpu-4gb", - image: str = "ubuntu-25-04-x64", + image: str = "ubuntu-25-10-x64", ssh_keys: list[str] | None = None, ssh_key_ids: list[int] | None = None, extra_tags: list[str] | None = None, diff --git a/dropkit/main.py b/dropkit/main.py index 442131b..535850c 100644 --- a/dropkit/main.py +++ b/dropkit/main.py @@ -1714,14 +1714,14 @@ def init( if images: image = prompt_with_help( "Default image", - default="ubuntu-25-04-x64", + default="ubuntu-25-10-x64", display_func=display_images, data=images, ) else: image = Prompt.ask( "[cyan]Default image[/cyan]", - default="ubuntu-25-04-x64", + default="ubuntu-25-10-x64", ) # Prompt for extra tags diff --git a/tests/test_config.py b/tests/test_config.py index 86ea06b..009648e 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -34,7 +34,7 @@ def valid_config_dict(): "defaults": { "region": "nyc3", "size": "s-2vcpu-4gb", - "image": "ubuntu-25-04-x64", + "image": "ubuntu-25-10-x64", "extra_tags": ["custom-tag"], }, "cloudinit": { @@ -98,12 +98,12 @@ def test_valid_config(self): config = DefaultsConfig( region="nyc3", size="s-2vcpu-4gb", - image="ubuntu-25-04-x64", + image="ubuntu-25-10-x64", extra_tags=["tag1", "tag2"], ) assert config.region == "nyc3" assert config.size == "s-2vcpu-4gb" - assert config.image == "ubuntu-25-04-x64" + assert config.image == "ubuntu-25-10-x64" assert config.extra_tags == ["tag1", "tag2"] def test_empty_region_fails(self): @@ -112,7 +112,7 @@ def test_empty_region_fails(self): DefaultsConfig( region="", size="s-2vcpu-4gb", - image="ubuntu-25-04-x64", + image="ubuntu-25-10-x64", ) def test_empty_size_fails(self): @@ -121,7 +121,7 @@ def test_empty_size_fails(self): DefaultsConfig( region="nyc3", size="", - image="ubuntu-25-04-x64", + image="ubuntu-25-10-x64", ) def test_empty_image_fails(self): @@ -138,7 +138,7 @@ def test_empty_extra_tags_allowed(self): config = DefaultsConfig( region="nyc3", size="s-2vcpu-4gb", - image="ubuntu-25-04-x64", + image="ubuntu-25-10-x64", extra_tags=[], ) assert config.extra_tags == [] @@ -148,7 +148,7 @@ def test_missing_extra_tags_defaults_to_empty(self): config = DefaultsConfig( region="nyc3", size="s-2vcpu-4gb", - image="ubuntu-25-04-x64", + image="ubuntu-25-10-x64", ) assert config.extra_tags == [] @@ -297,7 +297,7 @@ def test_create_default_config(self): username="testuser", region="nyc3", size="s-2vcpu-4gb", - image="ubuntu-25-04-x64", + image="ubuntu-25-10-x64", ssh_keys=["/path/to/key.pub"], ssh_key_ids=[12345], extra_tags=["tag1", "tag2"], @@ -345,7 +345,7 @@ def test_save_and_load_config(self, temp_config_dir, valid_config_dict, monkeypa username="testuser", region="sfo3", size="s-1vcpu-1gb", - image="ubuntu-25-04-x64", + image="ubuntu-25-10-x64", ssh_keys=["/path/to/key.pub"], ssh_key_ids=[98765], extra_tags=["test_tag"], From b389b54670646755dcb6a955482ef515a1dc6c48 Mon Sep 17 00:00:00 2001 From: Riccardo Schirone Date: Fri, 13 Mar 2026 14:11:28 +0100 Subject: [PATCH 2/2] Extract default region/size/image slugs into constants Replace duplicated hardcoded strings across config.py, main.py, and tests with DEFAULT_REGION, DEFAULT_SIZE, and DEFAULT_IMAGE constants defined in config.py. Co-Authored-By: Claude Opus 4.6 --- dropkit/config.py | 11 ++++++--- dropkit/main.py | 14 +++++------ tests/test_config.py | 57 +++++++++++++++++++++++--------------------- 3 files changed, 45 insertions(+), 37 deletions(-) diff --git a/dropkit/config.py b/dropkit/config.py index df87d6e..a9857c8 100644 --- a/dropkit/config.py +++ b/dropkit/config.py @@ -9,6 +9,11 @@ from cryptography.hazmat.primitives import serialization from pydantic import BaseModel, ConfigDict, Field, field_validator +# Default slugs for droplet creation +DEFAULT_REGION = "nyc3" +DEFAULT_SIZE = "s-2vcpu-4gb" +DEFAULT_IMAGE = "ubuntu-25-10-x64" + class DigitalOceanConfig(BaseModel): """DigitalOcean API configuration.""" @@ -296,9 +301,9 @@ def create_default_config( self, token: str, username: str, # noqa: ARG002 - kept for API compatibility, username derived from DO API - region: str = "nyc3", - size: str = "s-2vcpu-4gb", - image: str = "ubuntu-25-10-x64", + region: str = DEFAULT_REGION, + size: str = DEFAULT_SIZE, + image: str = DEFAULT_IMAGE, ssh_keys: list[str] | None = None, ssh_key_ids: list[int] | None = None, extra_tags: list[str] | None = None, diff --git a/dropkit/main.py b/dropkit/main.py index 535850c..5c9fcf0 100644 --- a/dropkit/main.py +++ b/dropkit/main.py @@ -18,7 +18,7 @@ from dropkit.api import DigitalOceanAPI, DigitalOceanAPIError from dropkit.cloudinit import render_cloud_init -from dropkit.config import Config, DropkitConfig +from dropkit.config import DEFAULT_IMAGE, DEFAULT_REGION, DEFAULT_SIZE, Config, DropkitConfig from dropkit.lock import requires_lock from dropkit.ssh_config import ( add_ssh_host, @@ -1686,42 +1686,42 @@ def init( if regions: region = prompt_with_help( "Default region", - default="nyc3", + default=DEFAULT_REGION, display_func=display_regions, data=regions, ) else: region = Prompt.ask( "[cyan]Default region[/cyan]", - default="nyc3", + default=DEFAULT_REGION, ) # Prompt for default size if sizes: size = prompt_with_help( "Default droplet size", - default="s-2vcpu-4gb", + default=DEFAULT_SIZE, display_func=display_sizes, data=sizes, ) else: size = Prompt.ask( "[cyan]Default droplet size[/cyan]", - default="s-2vcpu-4gb", + default=DEFAULT_SIZE, ) # Prompt for default image if images: image = prompt_with_help( "Default image", - default="ubuntu-25-10-x64", + default=DEFAULT_IMAGE, display_func=display_images, data=images, ) else: image = Prompt.ask( "[cyan]Default image[/cyan]", - default="ubuntu-25-10-x64", + default=DEFAULT_IMAGE, ) # Prompt for extra tags diff --git a/tests/test_config.py b/tests/test_config.py index 009648e..c4986ce 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -6,6 +6,9 @@ from pydantic import ValidationError from dropkit.config import ( + DEFAULT_IMAGE, + DEFAULT_REGION, + DEFAULT_SIZE, CloudInitConfig, Config, DefaultsConfig, @@ -32,9 +35,9 @@ def valid_config_dict(): "api_base": "https://api.digitalocean.com/v2", }, "defaults": { - "region": "nyc3", - "size": "s-2vcpu-4gb", - "image": "ubuntu-25-10-x64", + "region": DEFAULT_REGION, + "size": DEFAULT_SIZE, + "image": DEFAULT_IMAGE, "extra_tags": ["custom-tag"], }, "cloudinit": { @@ -96,14 +99,14 @@ class TestDefaultsConfig: def test_valid_config(self): """Test valid defaults config.""" config = DefaultsConfig( - region="nyc3", - size="s-2vcpu-4gb", - image="ubuntu-25-10-x64", + region=DEFAULT_REGION, + size=DEFAULT_SIZE, + image=DEFAULT_IMAGE, extra_tags=["tag1", "tag2"], ) - assert config.region == "nyc3" - assert config.size == "s-2vcpu-4gb" - assert config.image == "ubuntu-25-10-x64" + assert config.region == DEFAULT_REGION + assert config.size == DEFAULT_SIZE + assert config.image == DEFAULT_IMAGE assert config.extra_tags == ["tag1", "tag2"] def test_empty_region_fails(self): @@ -111,34 +114,34 @@ def test_empty_region_fails(self): with pytest.raises(ValidationError): DefaultsConfig( region="", - size="s-2vcpu-4gb", - image="ubuntu-25-10-x64", + size=DEFAULT_SIZE, + image=DEFAULT_IMAGE, ) def test_empty_size_fails(self): """Test that empty size fails validation.""" with pytest.raises(ValidationError): DefaultsConfig( - region="nyc3", + region=DEFAULT_REGION, size="", - image="ubuntu-25-10-x64", + image=DEFAULT_IMAGE, ) def test_empty_image_fails(self): """Test that empty image fails validation.""" with pytest.raises(ValidationError): DefaultsConfig( - region="nyc3", - size="s-2vcpu-4gb", + region=DEFAULT_REGION, + size=DEFAULT_SIZE, image="", ) def test_empty_extra_tags_allowed(self): """Test that empty extra_tags list is allowed.""" config = DefaultsConfig( - region="nyc3", - size="s-2vcpu-4gb", - image="ubuntu-25-10-x64", + region=DEFAULT_REGION, + size=DEFAULT_SIZE, + image=DEFAULT_IMAGE, extra_tags=[], ) assert config.extra_tags == [] @@ -146,9 +149,9 @@ def test_empty_extra_tags_allowed(self): def test_missing_extra_tags_defaults_to_empty(self): """Test that missing extra_tags defaults to empty list.""" config = DefaultsConfig( - region="nyc3", - size="s-2vcpu-4gb", - image="ubuntu-25-10-x64", + region=DEFAULT_REGION, + size=DEFAULT_SIZE, + image=DEFAULT_IMAGE, ) assert config.extra_tags == [] @@ -236,7 +239,7 @@ def test_valid_full_config(self, valid_config_dict): """Test valid full configuration.""" config = DropkitConfig(**valid_config_dict) assert config.digitalocean.token == "dop_v1_test_token_12345" - assert config.defaults.region == "nyc3" + assert config.defaults.region == DEFAULT_REGION assert config.cloudinit.ssh_keys[0] == "/home/user/.ssh/id_ed25519.pub" assert config.ssh.auto_update is True @@ -295,9 +298,9 @@ def test_create_default_config(self): config.create_default_config( token="test_token", username="testuser", - region="nyc3", - size="s-2vcpu-4gb", - image="ubuntu-25-10-x64", + region=DEFAULT_REGION, + size=DEFAULT_SIZE, + image=DEFAULT_IMAGE, ssh_keys=["/path/to/key.pub"], ssh_key_ids=[12345], extra_tags=["tag1", "tag2"], @@ -305,7 +308,7 @@ def test_create_default_config(self): # Should be able to access config now assert config.config.digitalocean.token == "test_token" - assert config.config.defaults.region == "nyc3" + assert config.config.defaults.region == DEFAULT_REGION assert config.config.defaults.extra_tags == ["tag1", "tag2"] assert config.config.cloudinit.ssh_key_ids == [12345] @@ -345,7 +348,7 @@ def test_save_and_load_config(self, temp_config_dir, valid_config_dict, monkeypa username="testuser", region="sfo3", size="s-1vcpu-1gb", - image="ubuntu-25-10-x64", + image=DEFAULT_IMAGE, ssh_keys=["/path/to/key.pub"], ssh_key_ids=[98765], extra_tags=["test_tag"],