Skip to content

Commit

Permalink
feat: support [email protected] devel rocks
Browse files Browse the repository at this point in the history
Includes a warning if using a devel base
  • Loading branch information
tigarmo committed Feb 7, 2024
1 parent d00d235 commit 4e8de46
Show file tree
Hide file tree
Showing 9 changed files with 133 additions and 14 deletions.
13 changes: 11 additions & 2 deletions docs/reference/rockcraft.yaml.rst
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ The rock version, used to tag the OCI image and name the rock file.
``base``
--------

**Type**: One of ``[email protected] | [email protected] | bare``
**Type**: One of ``[email protected] | [email protected] | [email protected] | bare``

**Required**: Yes

Expand All @@ -84,10 +84,14 @@ which is typically used with static binaries or
The notation "ubuntu:<channel>" is also supported for some channels, but this
format is deprecated and should be avoided.

.. note::
Base ``[email protected]`` is still unstable and under active development. To use
it, ``build-base`` *must* be ``devel``.

``build-base``
--------------

**Type**: One of ``[email protected] | [email protected]``
**Type**: One of ``[email protected] | [email protected] | devel``

**Required**: Yes, if ``base`` is ``bare``

Expand All @@ -101,6 +105,11 @@ the value of ``base``.
The notation "ubuntu:<channel>" is also supported for some channels, but this
format is deprecated and should be avoided.

.. note::
``devel`` is a "special" value that means "the next Ubuntu version, currently
in development". This means that the contents of this system changes
frequently and should not be relied on for production rocks.

``license``
-----------

Expand Down
37 changes: 34 additions & 3 deletions rockcraft/models/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,14 @@ def _validate_platform_set(cls, values: Mapping[str, Any]) -> Mapping[str, Any]:

DEPRECATED_COLON_BASES = ["ubuntu:20.04", "ubuntu:22.04"]

CURRENT_DEVEL_BASE = "[email protected]"

DEVEL_BASE_WARNING = (
"The development build-base should only be used for testing purposes, "
"as its contents are bound to change with the opening of new Ubuntu releases, "
"suddenly and without warning."
)


class NameStr(pydantic.ConstrainedStr):
"""Constrained string type only accepting valid rock names."""
Expand All @@ -133,8 +141,8 @@ class Project(YamlModelMixin, BaseProject):
description: str # type: ignore[reportIncompatibleVariableOverride]
rock_license: str = pydantic.Field(alias="license")
platforms: dict[str, Any]
base: Literal["bare", "[email protected]", "[email protected]"]
build_base: Literal["[email protected]", "[email protected]"] | None
base: Literal["bare", "[email protected]", "[email protected]", "[email protected]"]
build_base: Literal["[email protected]", "[email protected]", "devel"] | None
environment: dict[str, str] | None
run_user: _RunUser
services: dict[str, Service] | None
Expand All @@ -154,7 +162,12 @@ class Config(CraftBaseConfig): # pylint: disable=too-few-public-methods
def effective_base(self) -> bases.BaseName:
"""Get the Base name for craft-providers."""
base = super().effective_base
name, channel = base.split("@")

if base == "devel":
name, channel = "ubuntu", "devel"
else:
name, channel = base.split("@")

return bases.BaseName(name, channel)

@pydantic.root_validator(pre=True)
Expand Down Expand Up @@ -197,6 +210,24 @@ def _validate_title(cls, title: str | None, values: Mapping[str, Any]) -> str:
title = values.get("name", "")
return cast(str, title)

@pydantic.root_validator(skip_on_failure=True)
@classmethod
def _validate_devel_base(cls, values: Mapping[str, Any]) -> Mapping[str, Any]:
"""If 'base' is currently unstable, 'build-base' must be 'devel'."""
base = values.get("base")
build_base = values.get("build_base")

if base == CURRENT_DEVEL_BASE and build_base != "devel":
raise CraftValidationError(
f'To use the unstable base "{CURRENT_DEVEL_BASE}", '
'"build-base" must be "devel".'
)

if base == CURRENT_DEVEL_BASE:
craft_cli.emit.message(DEVEL_BASE_WARNING)

return values

@pydantic.validator("build_base", always=True)
@classmethod
def _validate_build_base(
Expand Down
6 changes: 4 additions & 2 deletions schema/rockcraft.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@
"enum": [
"bare",
"[email protected]",
"[email protected]"
"[email protected]",
"[email protected]"
],
"type": "string"
},
Expand Down Expand Up @@ -95,7 +96,8 @@
"title": "Build-Base",
"enum": [
"[email protected]",
"[email protected]"
"[email protected]",
"devel"
],
"type": "string"
},
Expand Down
11 changes: 6 additions & 5 deletions tests/integration/plugins/test_python_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from craft_parts.utils.os_utils import OsRelease

from rockcraft import plugins
from rockcraft.models.project import Project
from rockcraft.models.project import CURRENT_DEVEL_BASE, Project
from rockcraft.plugins.python_plugin import SITECUSTOMIZE_TEMPLATE
from tests.testing.project import create_project
from tests.util import ubuntu_only
Expand Down Expand Up @@ -60,10 +60,11 @@ def create_python_project(base, extra_part_props=None) -> Project:
}
}

return create_project(
base=base,
parts=parts,
)
build_base = None
if base == CURRENT_DEVEL_BASE:
build_base = "devel"

return create_project(base=base, parts=parts, build_base=build_base)


@dataclass
Expand Down
18 changes: 18 additions & 0 deletions tests/spread/general/base-devel/rockcraft.orig.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: base-devel
base: placeholder-base
build-base: devel
version: '0.1'
summary: A project using the "devel" build-base
description: A project using the "devel" build-base
license: GPL-3.0
platforms:
amd64:

parts:
from-chisel-slices:
plugin: nil
stage-packages: [dotnet-runtime-8.0_libs]

from-deb:
plugin: nil
stage-packages: [hello]
12 changes: 12 additions & 0 deletions tests/spread/general/base-devel/task.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
summary: Build rocks using the "devel" build-base
environment:
BASE/base_2404: "[email protected]"
BASE/bare: "bare"
execute: |
# Make sure the yaml file has the "placeholder-base" string, and replace
# it with the correct base.
grep placeholder-base rockcraft.orig.yaml
sed "s/placeholder-base/$BASE/" rockcraft.orig.yaml > rockcraft.yaml
# Build the rock & load it into docker
run_rockcraft pack
5 changes: 5 additions & 0 deletions tests/spread/general/plugin-python/base-2404/rockcraft.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
name: base-2404
base: [email protected]
build-base: devel

# Remaining contents will come from "parts.yaml"
1 change: 1 addition & 0 deletions tests/spread/general/plugin-python/task.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ summary: Python plugin tests
environment:
SCENARIO/base_2004: base-2004
SCENARIO/base_2204: base-2204
SCENARIO/base_2404: base-2404
SCENARIO/bare_build_2004: bare-build-2004
SCENARIO/bare_build_2204: bare-build-2204
execute: |
Expand Down
44 changes: 42 additions & 2 deletions tests/unit/test_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,13 @@

from rockcraft.errors import ProjectLoadError
from rockcraft.models import Project
from rockcraft.models.project import INVALID_NAME_MESSAGE, Platform, load_project
from rockcraft.models.project import (
CURRENT_DEVEL_BASE,
DEVEL_BASE_WARNING,
INVALID_NAME_MESSAGE,
Platform,
load_project,
)
from rockcraft.pebble import Service

_ARCH_MAPPING = {"x86": "amd64", "x64": "amd64"}
Expand Down Expand Up @@ -233,7 +239,8 @@ def test_project_base_invalid(yaml_loaded_data):
load_project_yaml(yaml_loaded_data)
assert str(err.value) == (
"Bad rockcraft.yaml content:\n"
"- unexpected value; permitted: 'bare', '[email protected]', '[email protected]' (in field 'base')"
"- unexpected value; permitted: 'bare', '[email protected]', "
"'[email protected]', '[email protected]' (in field 'base')"
)


Expand Down Expand Up @@ -706,3 +713,36 @@ def test_project_get_build_plan(yaml_loaded_data, platforms, expected_build_info
yaml_loaded_data["platforms"] = platforms
project = Project.unmarshal(yaml_loaded_data)
assert project.get_build_plan() == expected_build_infos


def test_project_devel_base(yaml_loaded_data):
yaml_loaded_data["base"] = CURRENT_DEVEL_BASE
yaml_loaded_data["build-base"] = "[email protected]"

with pytest.raises(CraftValidationError) as err:
_ = Project.unmarshal(yaml_loaded_data)

expected = (
f'To use the unstable base "{CURRENT_DEVEL_BASE}", '
f'"build-base" must be "devel".'
)
assert str(err.value) == expected


def test_get_effective_devel_base(yaml_loaded_data):
yaml_loaded_data["base"] = CURRENT_DEVEL_BASE
yaml_loaded_data["build-base"] = "devel"
project = Project.unmarshal(yaml_loaded_data)

base = project.effective_base
assert base.name == "ubuntu"
assert base.version == "devel"


def test_devel_base_warning(yaml_loaded_data, emitter):
yaml_loaded_data["base"] = CURRENT_DEVEL_BASE
yaml_loaded_data["build-base"] = "devel"
del yaml_loaded_data["entrypoint-service"]
_ = Project.unmarshal(yaml_loaded_data)

emitter.assert_message(DEVEL_BASE_WARNING)

0 comments on commit 4e8de46

Please sign in to comment.