Skip to content
Draft
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
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
name: CI (docker)
name: Template for CI (container)

on:
push:
branches:
- main
pull_request:
workflow_dispatch:
workflow_call:
inputs:
container_cmd:
required: true
type: string

permissions:
contents: read

env:
CONTAINER_CMD: ${{ inputs.container_cmd }}

jobs:
build-and-run:
name: Build and run
Expand All @@ -25,9 +28,9 @@ jobs:
run: make build

- name: Run --help
run: docker run --rm nava-platform-cli --help
run: ${CONTAINER_CMD} run --rm nava-platform-cli --help

- name: Run e2e through docker-wrapper
- name: Run e2e through container-wrapper
env:
CMD: ./bin/docker-wrapper
CMD: ./bin/container-wrapper
run: make test-e2e
22 changes: 22 additions & 0 deletions .github/workflows/ci-container.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: CI (container)

on:
push:
branches:
- main
pull_request:
workflow_dispatch:

permissions:
contents: read

jobs:
ci:
strategy:
fail-fast: false
matrix:
container_cmd: [docker, podman]

uses: ./.github/workflows/ci-container-template.yml
with:
container_cmd: ${{ matrix.container_cmd }}
6 changes: 3 additions & 3 deletions Dockerfile → Containerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# renovate: datasource=python-version depName=python
ARG PYTHON_VERSION=3.12

FROM ghcr.io/astral-sh/uv:python$PYTHON_VERSION-trixie-slim@sha256:36cdfbf910c8b0f651355c013e7ece9678f4ecbf030a9fd9e6779de421189805
FROM ghcr.io/astral-sh/uv:python$PYTHON_VERSION-trixie-slim@sha256:36cdfbf910c8b0f651355c013e7ece9678f4ecbf030a9fd9e6779de421189805

# allow all users to get into "home", like git checking for a global ignore
# file, until better user juggling in the future
Expand Down Expand Up @@ -32,7 +32,7 @@ RUN --mount=type=cache,target=/root/.cache/uv \

ENV PATH="/app/.venv/bin:$PATH"

COPY bin/docker-entry /usr/local/bin
COPY bin/container-entry /usr/local/bin

WORKDIR /project-dir
ENTRYPOINT ["docker-entry"]
ENTRYPOINT ["container-entry"]
10 changes: 6 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ PY_SRCS := nava tests

PY_RUN ?= uv run --frozen

CONTAINER_CMD ?= docker
export CONTAINER_CMD

ifdef CI
FMT_ARGS :=--check
Expand All @@ -14,8 +16,8 @@ FMT_ARGS :=
LINT_ARGS :=--fix
endif

build: ## Build docker image
docker build --tag $(PKG_NAME) .
build: ## Build container image
$(CONTAINER_CMD) build --tag $(PKG_NAME) --file Containerfile .

check: ## Run checks
check: check-static test test-e2e
Expand All @@ -31,7 +33,7 @@ clean: clean-docs
find . -type d -name .mypy_cache -print -exec rm -r {} +
find . -type d -name .pytest_cache -print -exec rm -r {} +
$(PY_RUN) ruff clean
-docker image rm $(PKG_NAME)
-$(CONTAINER_CMD) image rm $(PKG_NAME)

clean-docs: ## Remove generated doc files
rm -f docs/index.md
Expand Down Expand Up @@ -122,7 +124,7 @@ test-watch: ## Run tests continually and watch for changes
$(PY_RUN) pytest-watcher --clear $(PY_SRCS) $(args)

update-container-digest: ## Update container digests to latest
./bin/update-container-digest Dockerfile
./bin/update-container-digest Containerfile

help: ## Display this help screen
@grep -Eh '^[[:print:]]+:.*?##' $(MAKEFILE_LIST) | \
Expand Down
File renamed without changes.
47 changes: 33 additions & 14 deletions bin/docker-wrapper → bin/container-wrapper
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#!/usr/bin/env bash
#
# Wrap running `nava-platform` via Docker. Pass arguments as you would to
# Wrap running `nava-platform` via a container. Pass arguments as you would to
# `nava-platform` itself.
#
# Since the tool heavily involves manipulating files on the host system, some of
# which are in locations that may need created first, it can be fiddly to
# manually run via Docker.
# manually run.
#
# So this script tries to automate the annoying parts for common situations. To
# not explode in complexity, it does make some assumptions (or reserves the
Expand All @@ -15,8 +15,12 @@
#
set -euo pipefail

set -x

CONTAINER_CMD=${CONTAINER_CMD:-docker}

processed_args=()
docker_flags=()
run_flags=()
detected_host_paths=()

looks_like_path() {
Expand All @@ -30,16 +34,31 @@ case "${uname_out}" in
*) host_os="UNKNOWN:${uname_out}"
esac

# not strictly required with magic in `docker-entry` script and mostly for when
# running on Linux, but explicitly run as host user to help avoid any file
# permission issues with mounted locations from the host file system
docker_flags+=(--user "$(id -u):$(id -g)")
# TODO: make a consolidated setting/detection for rootless podman which seems to
# have broken --userns=keep-id/--userns=keep-id:uid=$(id -u),gid=$(id -g)
# handling so we need to let things inside the container run as root to most
# seamlessly map created files back to the hosts uid/gid

# mostly for when running on Linux, but when using a daemon running as root,
# explicitly run the container as host user to help avoid any file permission
# issues with mounted locations from the host file system
if [[ "${CONTAINER_CMD}" == "docker" ]]; then
run_flags+=(--user "$(id -u):$(id -g)")
fi


if [[ "${CONTAINER_CMD}" == "docker" ]]; then
CONTAINER_USER_HOME=""
else
# otherwise the host user is going to be map to root user in the container
CONTAINER_USER_HOME="/root"
fi

# connect the host git config if present, for better chance committing with work
# inside the container (theoretically someone may not have their name/email
# configured even if the config file exists)
if [[ -e "$HOME/.gitconfig" ]]; then
docker_flags+=("-v=$HOME/.gitconfig:/.gitconfig")
run_flags+=("-v=$HOME/.gitconfig:${CONTAINER_USER_HOME}/.gitconfig")
fi

# figure out what location to mount for logs
Expand All @@ -59,7 +78,7 @@ fi
if [[ ! -d "${HOST_LOG_DIR}" ]]; then
mkdir -p "${HOST_LOG_DIR}"
fi
docker_flags+=("-v=${HOST_LOG_DIR}:/.local/state/nava-platform-cli/log:z")
run_flags+=("-v=${HOST_LOG_DIR}:${CONTAINER_USER_HOME}/.local/state/nava-platform-cli/log:z")

# process the script arguments
for ((i=1;i<=$#;i++))
Expand All @@ -83,20 +102,20 @@ do
abs_value=$(realpath "${value}")
detected_host_paths+=("${abs_value}")

docker_flags+=("-v=${abs_value}:${abs_value}:z")
run_flags+=("-v=${abs_value}:${abs_value}:z")
processed_args+=("${abs_value}")
else
processed_args+=("${value}")
fi
done

# if host paths don't exist yet, particularly directories, create them before
# Docker does (with incorrect permissions) when it goes to mount them as a
# volume
# the container runtime does (with incorrect permissions) when it goes to mount
# them as a volume
#
# TODO: this is basically only to support initializing a project with a
# template. We could isolate that functionality in an `init` command that we
# have simpler special handling for or just not support that mode via docker?
# have simpler special handling for or just not support that mode via a container?
for dpath in "${detected_host_paths[@]}"; do
if [[ ! -e "${dpath}" ]]; then
# basically, does the path look like a directory?
Expand All @@ -110,4 +129,4 @@ for dpath in "${detected_host_paths[@]}"; do
fi
done

docker run --interactive --rm "${docker_flags[@]}" nava-platform-cli "${processed_args[@]}"
${CONTAINER_CMD} run --interactive --rm "${run_flags[@]}" nava-platform-cli "${processed_args[@]}"
6 changes: 3 additions & 3 deletions docs/getting-started/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,15 +140,15 @@ yourself.
for simplified execution:

```sh
./bin/docker-wrapper infra install ./my_project_directory
./bin/container-wrapper infra install ./my_project_directory
```

(or create an alias in your shell like `alias nava-platform =
<path_to_checkout>/bin/docker-wrapper`)
<path_to_checkout>/bin/container-wrapper`)

!!! warning

The `docker-wrapper` script makes assumptions about your
The `container-wrapper` script makes assumptions about your
environment. Review the script comments before use.

??? note "Running manually"
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ for a overview:
├── nava/ # CLI app source code
├── tests/ # Unit tests
├── tests-e2e/ # End-to-end tests for CLI behavior
├── Dockerfile # Source for the container build of the CLI
├── Containerfile # Source for the container build of the CLI
├── flake.lock # Nix
├── flake.nix # Nix
├── Makefile # Main development interface
Expand Down
34 changes: 23 additions & 11 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,6 @@
'';
});

# TODO: could add docker-client here?
generalDevPackages = with pkgs; [
# dev tooling
gnumake
Expand All @@ -144,38 +143,38 @@
skopeo
];

dockerEntryPkg =
containerEntryPkg =
let
scriptDeps = [
pkgs.coreutils # for id, stat
pkgs.util-linux # for setpriv
];
in
pkgs.stdenv.mkDerivation {
name = "docker-entry";
name = "container-entry";
src = pkgs.lib.fileset.toSource {
root = ./.;
fileset = ./bin/docker-entry;
fileset = ./bin/container-entry;
};
nativeBuildInputs = [ pkgs.makeWrapper ];
installPhase = ''
mkdir -p $out/bin
install $src/bin/docker-entry $out/bin/docker-entry
install $src/bin/container-entry $out/bin/container-entry

wrapProgram $out/bin/docker-entry --prefix PATH : ${pkgs.lib.makeBinPath scriptDeps}
wrapProgram $out/bin/container-entry --prefix PATH : ${pkgs.lib.makeBinPath scriptDeps}
'';
};

dockerBuildArgs = {
containerBuildArgs = {
name = "nava-platform-cli";
tag = "latest";
contents = [
dockerEntryPkg
containerEntryPkg
nava-platform-cli
]
++ runtimePackages;
config = {
Entrypoint = "docker-entry";
Entrypoint = "container-entry";
WorkingDir = "/project-dir";
};
};
Expand Down Expand Up @@ -214,8 +213,8 @@
nava-platform-cli-bin = nava-platform-cli-bin;
docs = cli-docs-site;

docker = pkgs.dockerTools.buildLayeredImage dockerBuildArgs;
dockerStream = pkgs.dockerTools.streamLayeredImage dockerBuildArgs;
container = pkgs.dockerTools.buildLayeredImage containerBuildArgs;
containerStream = pkgs.dockerTools.streamLayeredImage containerBuildArgs;
};

# nix run .
Expand Down Expand Up @@ -350,6 +349,19 @@
pkgs.pipx
];
};

# Shell for container interaction. For testing running the package via
# a container runtime or other needs.
podman = pkgs.mkShell {
packages = [
generalDevPackages
pkgs.podman
];

env = {
CONTAINER_CMD = "podman";
};
};
};

legacyPackages = pkgs;
Expand Down