Skip to content

Charmcraft wrapper with support for build context#1

Closed
arturo-seijas wants to merge 15 commits intomainfrom
charmcraft-wrapper
Closed

Charmcraft wrapper with support for build context#1
arturo-seijas wants to merge 15 commits intomainfrom
charmcraft-wrapper

Conversation

@arturo-seijas
Copy link
Copy Markdown
Collaborator

@arturo-seijas arturo-seijas commented Mar 11, 2026

A wrapper around charmcraft to allos to specify an addtional --build-context argument to change the context charmcraft will be able to access when building.
For it to work, the charmcraft.yaml file will need to define the following sections on the uv plugin:

    build-environment:
      - UV_WORKING_DIR: .
    override-build: |
      craftctl default
      cp --archive --recursive --reflink=auto $CRAFT_PART_BUILD/$UV_WORKING_DIR/src $CRAFT_PART_INSTALL/src
      cp --archive --recursive --reflink=auto $CRAFT_PART_BUILD/$UV_WORKING_DIR/lib $CRAFT_PART_INSTALL/lib

See canonical/falco-operators#114 for a working example

Comment thread charmbuild/files.py Outdated
Comment thread charmbuild/main.py Outdated
@javierdelapuente
Copy link
Copy Markdown

@james-garner-canonical Can you have a look at this PR, as I think you have been involved in similar cases

@james-garner-canonical
Copy link
Copy Markdown

Hi @arturo-seijas, @javierdelapuente, I had a quick look over this PR. To be honest, I think this tooling is a bit too much for the task at hand.

Ideally charms would avoid wrapping charmcraft pack in CI at all to avoid charm build processes becoming non-standard, but charm monorepos are in an awkward spot right now as the workarounds required to avoid wrapping pack can get pretty complex (because charmcraft pack only mounts the charm's directory, meaning that shared, local dependencies aren't accessible).

My preference here would be for a very thin, interim wrapper so you can focus on charm and library logic right now, and more easily iron out the build process in future when there's a standardised approach for charm monorepos.


For example, assuming your repo is laid out like this:

$repo/
  common/  # a Python package
  $charmdir/
    src/charm.py
    common -> ../common  # a symlink
    charmcraft.yaml
    pyproject.toml

Where pyproject.toml is managed by uv and looks like this (I'm assuming the charm uses the uv plugin):

[project]
# ...
dependencies = [
    "common",
    # ...
]
# ...

[tool.uv.sources]
common = { path = "./common", editable = true }

Then you could wrap charmcraft pack like this:

rm --recursive --force ".packed-$charmdir"
cp --recursive --dereference "$charmdir" ".packed-$charmdir"
cd ".packed-$charmdir"
charmcraft pack

This recipe could go in your justfile / tox.ini/ Makefile / etc, or just be defined directly in your integration testing CI job, depending what works best for your local and CI workflows.


Happy to chat more about this, feel free to message me or set up a meeting.

@arturo-seijas
Copy link
Copy Markdown
Collaborator Author

Hi @arturo-seijas, @javierdelapuente, I had a quick look over this PR. To be honest, I think this tooling is a bit too much for the task at hand.

Ideally charms would avoid wrapping charmcraft pack in CI at all to avoid charm build processes becoming non-standard, but charm monorepos are in an awkward spot right now as the workarounds required to avoid wrapping pack can get pretty complex (because charmcraft pack only mounts the charm's directory, meaning that shared, local dependencies aren't accessible).

My preference here would be for a very thin, interim wrapper so you can focus on charm and library logic right now, and more easily iron out the build process in future when there's a standardised approach for charm monorepos.

For example, assuming your repo is laid out like this:

$repo/
  common/  # a Python package
  $charmdir/
    src/charm.py
    common -> ../common  # a symlink
    charmcraft.yaml
    pyproject.toml

Where pyproject.toml is managed by uv and looks like this (I'm assuming the charm uses the uv plugin):

[project]
# ...
dependencies = [
    "common",
    # ...
]
# ...

[tool.uv.sources]
common = { path = "./common", editable = true }

Then you could wrap charmcraft pack like this:

rm --recursive --force ".packed-$charmdir"
cp --recursive --dereference "$charmdir" ".packed-$charmdir"
cd ".packed-$charmdir"
charmcraft pack

This recipe could go in your justfile / tox.ini/ Makefile / etc, or just be defined directly in your integration testing CI job, depending what works best for your local and CI workflows.

Happy to chat more about this, feel free to message me or set up a meeting.

Hi @james-garner-canonical , the advantages I can see of the proposed approach are:

  • There's no need to manually set up anything on the repository side, same cognitive complexity of the solution and it doesn't introduce room for human errors when setting up new dependencies
  • This is a Python package, so we can easily distribute it. Makefiles and the likes are not the best solution for code reuse

@seb4stien seb4stien requested review from cbartz and weiiwang01 March 25, 2026 11:16
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a new charmbuild Python CLI that wraps charmcraft to support building with an additional --build-context directory (by copying sources into a temp dir and patching charmcraft.yaml for uv’s UV_WORKING_DIR use case).

Changes:

  • Introduces charmbuild CLI and file helpers to copy build context into a temporary directory and patch charmcraft.yaml for uv plugin builds.
  • Adds ADRs and README documenting the design/usage.
  • Adds pytest coverage for argument parsing, charmcraft invocation wiring, context copying, YAML patching, and artifact copying.

Reviewed changes

Copilot reviewed 10 out of 11 changed files in this pull request and generated 12 comments.

Show a summary per file
File Description
charmbuild/main.py Implements the CLI wrapper, argument parsing, temp build dir flow, and charmcraft invocation.
charmbuild/files.py Implements context copying, charmcraft.yaml patching for uv UV_WORKING_DIR, lib relocation, and .charm artifact copying.
charmbuild/__init__.py Package marker.
tests/test_main.py Tests CLI parsing and main flow behavior via mocks.
tests/test_files.py Tests context copying, YAML patching, lib movement, charm name extraction, and .charm copying.
tests/__init__.py Test package marker.
README.md Documents charmbuild goals and usage, including --build-context.
pyproject.toml Defines package metadata, dependencies, pytest config, and console script entrypoint.
docs/adr/0001-record-architecture-decisions.md Adds ADR process record.
docs/adr/0002-build-context-implementation.md Documents chosen build-context implementation approach.
.gitignore Ignores Python __pycache__.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread charmbuild/main.py
Comment thread charmbuild/main.py
Comment thread charmbuild/main.py
Comment thread charmbuild/main.py
Comment thread charmbuild/main.py Outdated
Comment thread README.md
Comment thread charmbuild/main.py Outdated
Comment thread docs/adr/0002-build-context-implementation.md Outdated
Comment thread pyproject.toml Outdated
Comment thread charmbuild/files.py Outdated
arturo-seijas and others added 10 commits March 30, 2026 08:53
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
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.

4 participants