Skip to content

Add models for a single YAML configuration file#155

Merged
bschwedler merged 29 commits intomainfrom
single-yaml-config
Aug 14, 2025
Merged

Add models for a single YAML configuration file#155
bschwedler merged 29 commits intomainfrom
single-yaml-config

Conversation

@ianpittwood
Copy link
Contributor

@ianpittwood ianpittwood commented Jul 31, 2025

  • Remodel the Bakery configuration file as a single YAML file.
  • Divide up modeling and functionality as follows:
    • BakeryConfig - Manager for the BakeryConfigDocument. This class will handle nearly all interactions from the CLI and other code in the future.
      • BakeryConfigDocument - Top-level model for the configuration file with fields for the three main sections: repository, registries, and images. It also registers the base path for the project (the directory in which the config resides). Previous validators should be implemented. I also added a capability for a lot of these objects to register themselves as a parent in each child to make it easier to traverse back and forth across the config.
        • Repository - Basically a direct rip of the existing Repository model. The only major difference is that contact info is now stored as a HashableNameEmail type, a child of Pydantic's NameEmail with a hash function for deduplication. url is now stored as an HttpUrl type too to enforce it being a URL. I did add a pre-validator to prepend https:// if it's not that since it causes errors otherwise.
        • Registry - Direct rip of existing Registry model.
        • Image - Represents an Image in the config and its variants (rename of types such as min and std) and versions. Registries can also be added here to the global registries or overridden entirely using overrideRegistries. Image-wide tagPatterns can also be set here.
          • ImageVariant - Represents a variant of an image like Standard (std) or Minimal (min). Standard is no longer the de factor primary variant and a primary should instead be specified by setting primary. The extension searched for when searching for Containerfiles (ex Containerfile.min.ubuntu2204) can now be set using extension, but it will automatically be guessed at if not provided using the name. The tagDisplayName can also be overridden for what is provided to tag pattern rendering. Variants can also add tag patterns, but they cannot currently modify registries.
            • If not provided, Image uses "Standard" and "Minimal" variants by default where "Standard" is set as primary. They also using the shortened names std and min respectively for the extension and tag display names respectively.
          • ImageVersion - Represents a version of the image. It now allows overriding the directory name via the subpath to make it so we can shorten Workbench versions to their core versions without metadata on directory names if we want. The verison still takes the latest flag and a list of os. Versions can set their own registries and override registries, but cannot set their own tags.
            • ImageVersionOS - Represents an operating system used with a version. The OS config still retains the primary flag for tagging purposes. It also adds extension and tagDisplayName fields to override the behavior for Containerfile matching and how tags are abbreviated.
          • TagPattern - Represents a Jinja2 string pattern to render into a tag suffix. There's a default generator for these that should cover existing cases. There's an enum that represents filters for the tags. There's no complex logic currently implemented and they just use AND for each filter applied.

ianpittwood and others added 29 commits July 9, 2025 12:58
…ormation (registry/repository info) from config
Add pre-validators to properly interpret a dictionary with "name" and "email" values or a string to defer validation to NameEmail
Upgrade Pydantic to allow utilization of validated data in default_factory functions

Make TagPattern objects hashable
Add validation for version dupes

Add validation for image dupes

Add validation for variant dupes
@ianpittwood ianpittwood requested a review from bschwedler as a code owner July 31, 2025 22:49
@github-actions
Copy link

Test Results

375 tests   373 ✅  1m 15s ⏱️
  1 suites    2 💤
  1 files      0 ❌

Results for commit 59be1fe.

Copy link
Contributor

@bschwedler bschwedler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm really liking the direction of this. Feel free to merge this as you work on pulling in the functionality in the follow-up PR.

My comments generally fall into two groups:

Optional fields

I am getting several warnings for missing parmaeters in model initialization. This occurs when we initialize a pydantic model without all of the fields.

Type assignments

I would like to do all we can to make type/param validation required since others will be using this tool.
pylance is reporting several issues with mismatched types.

I think it's time to start enforcing types as part of the pre-commit hook and in CI.



class GossOptions(ToolOptions):
tool: Literal["goss"] = "goss"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This complains that tool is not the same type (str) as the parent class.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have zero clue how to fix this. I found a Pydantic issue about abstract properties, but attempting to implement a discriminator that way results in errors.


class Registry(BakeryYAMLModel):
host: str
namespace: Annotated[str | None, Field(default=None)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be optional

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Python recommends doing the | None syntax over using Optional, but they are functionally equivalent.

https://stackoverflow.com/questions/69440494/python-3-10-optionaltype-or-type-none

Comment on lines +27 to +32
url: HttpUrl
vendor: Annotated[str, Field(default="Posit Software, PBC")]
maintainer: Annotated[
HashableNameEmail, Field(default=NameEmail(name="Posit Docker Team", email="docker@posit.co"))
]
authors: Annotated[list[HashableNameEmail], Field(default_factory=list)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe only url is required, so we should make th other fields optional

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The defaults handle that since all fields should be set or defaulted.

"""Prepend 'https://' to the URL if it does not already start with it"""
if isinstance(value, str):
if not value.startswith("https://"):
value = f"https://{value}"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type "str" is not assignable to declared type "AnyUrl"
  "str" is not assignable to "Url"PylancereportAssignmentType

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed the type hints to value: Any and -> Any which should satisfy it. Since it's a before validator, we should be able to take any value. In this case, I wanted to defer the conversion of the string to HttpUrl to Pydantic's own validator. If there's a better way of doing that though, let me know.

@bschwedler bschwedler merged commit 16b71fb into main Aug 14, 2025
3 checks passed
@bschwedler bschwedler deleted the single-yaml-config branch August 14, 2025 17:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants