Skip to content

Commit 5112ed2

Browse files
committed
add a dockerfile and all the stuff to publish
Closes #131
1 parent f6838e6 commit 5112ed2

File tree

9 files changed

+335
-6
lines changed

9 files changed

+335
-6
lines changed

.dockerignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.venv
2+
dist/

.github/workflows/ci.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ name: CI
22

33
on:
44
push:
5-
branches: [main]
5+
branches:
6+
- main
67
pull_request:
78

89
jobs:
@@ -23,11 +24,14 @@ jobs:
2324
cache-python: true
2425
- name: Install bats
2526
uses: bats-core/[email protected]
27+
id: setup-bats
2628
- name: Install dependencies
2729
run: just sync
2830
- name: Run tests
2931
run: just test
3032
- name: Run bats
3133
run: just bats
34+
env:
35+
BATS_LIB_PATH: ${{ steps.setup-bats.outputs.lib-path }}
3236
- name: Lint
3337
run: just lint

.github/workflows/docker.yml

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
name: Docker
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
tags:
8+
- 'v*'
9+
pull_request:
10+
branches:
11+
- main
12+
schedule:
13+
- cron: '0 0 * * 0' # Weekly on Sunday at midnight UTC
14+
15+
jobs:
16+
build:
17+
runs-on: ubuntu-latest
18+
permissions:
19+
contents: read
20+
packages: write
21+
steps:
22+
- uses: actions/checkout@v6
23+
with:
24+
fetch-depth: 0
25+
26+
- name: Checkout latest tag on schedule
27+
if: github.event_name == 'schedule'
28+
run: |
29+
git checkout $(git describe --tags --abbrev=0)
30+
31+
- uses: astral-sh/setup-uv@v7
32+
33+
- name: Get version
34+
id: version
35+
run: |
36+
VERSION=$(uv version --short)
37+
echo "version=$VERSION" >> $GITHUB_OUTPUT
38+
39+
- name: Set up Docker Buildx
40+
uses: docker/setup-buildx-action@v3
41+
42+
- name: Login to GitHub Container Registry
43+
if: github.event_name != 'pull_request'
44+
uses: docker/login-action@v3
45+
with:
46+
registry: ghcr.io
47+
username: ${{ github.actor }}
48+
password: ${{ secrets.GITHUB_TOKEN }}
49+
50+
- name: Build and push
51+
uses: docker/bake-action@v6
52+
with:
53+
push: ${{ github.event_name != 'pull_request' }}
54+
set: |
55+
*.cache-from=type=gha
56+
*.cache-to=type=gha,mode=max
57+
env:
58+
VERSION: ${{ steps.version.outputs.version }}
59+
LATEST_TAG: ${{ github.ref == 'refs/heads/main' && 'main' || 'latest' }}

Dockerfile

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
FROM cgr.dev/chainguard/wolfi-base:latest AS build
2+
COPY --from=ghcr.io/astral-sh/uv:0.9 /uv /bin
3+
4+
USER nonroot
5+
6+
WORKDIR /app
7+
8+
COPY . /app
9+
RUN uv sync \
10+
--verbose --no-dev --all-extras --locked \
11+
--no-cache-dir --no-editable --compile-bytecode \
12+
&& rm -rf /home/nonroot/.local/share/uv/python/cpython-*-gnu/share \
13+
&& rm -rf /home/nonroot/.local/share/uv/python/cpython-*-gnu/lib/tcl8* \
14+
&& rm -rf /home/nonroot/.local/share/uv/python/cpython-*-gnu/lib/libtcl8* \
15+
&& rm -rf /home/nonroot/.local/share/uv/python/cpython-*-gnu/lib/tk8* \
16+
&& rm -rf /home/nonroot/.local/share/uv/python/cpython-*-gnu/lib/libtk8*
17+
18+
RUN /app/.venv/bin/jinja2 --version
19+
20+
FROM cgr.dev/chainguard/wolfi-base:latest
21+
COPY --from=build --chown=nonroot:nonroot \
22+
/home/nonroot/.local/share/uv/ /home/nonroot/.local/share/uv/
23+
COPY --from=build --chown=nonroot:nonroot \
24+
/app/.venv/ /app/.venv/
25+
26+
USER nonroot
27+
28+
ENTRYPOINT ["/app/.venv/bin/jinja2"]
29+
CMD ["--help"]

Justfile

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,76 @@
1+
[default]
2+
[private]
13
default:
24
@just --list
35

6+
[doc('Install all dependencies')]
7+
[group('dev')]
48
sync:
59
uv sync --all-groups --all-extras
610

11+
[doc('Format code')]
12+
[group('dev')]
13+
fmt:
14+
uv run ruff check --select I --fix
15+
uv run ruff format
16+
17+
[doc('Remove build artifacts')]
18+
[group('dev')]
19+
clean:
20+
rm -rf dist .pytest_cache .ruff_cache
21+
22+
[doc('Run pytest tests')]
23+
[group('test')]
724
test:
825
uv run pytest -v
926

27+
[doc('Run bats integration tests')]
28+
[group('test')]
1029
bats:
1130
bats -T tests/bats
1231

32+
[doc('Run all tests')]
33+
[group('test')]
1334
test-all: test bats
1435

36+
[doc('Run linters')]
37+
[group('test')]
1538
lint:
1639
uv run ruff check
1740
uv run ty check
1841

42+
[doc('Benchmark startup time')]
43+
[group('bench')]
1944
bench-startup:
2045
hyperfine --warmup 3 --min-runs 10 ".venv/bin/jinja2 --version"
2146

22-
fmt:
23-
uv run ruff check --select I --fix
24-
uv run ruff format
47+
[doc('Build docker image')]
48+
[group('docker')]
49+
docker:
50+
docker build --rm -t jinja2-cli .
2551

52+
[doc('Print docker bake configuration')]
53+
[group('docker')]
54+
bake:
55+
VERSION=$(uv version --short) LATEST_TAG=dev \
56+
docker buildx bake --print
57+
58+
[doc('Build distribution packages')]
59+
[group('release')]
2660
build: clean
2761
uv build
2862

63+
[doc('Publish to PyPI')]
64+
[group('release')]
2965
publish: build
3066
uv publish
3167

32-
clean:
33-
rm -rf dist .pytest_cache .ruff_cache
68+
[doc('Bump version, commit, tag, and push')]
69+
[group('release')]
70+
bump kind:
71+
git diff --quiet --exit-code
72+
uv version --bump {{ kind }}
73+
git commit -am "bump $(uv version --short)"
74+
git tag -a "v$(uv version --short)" -a "v$(uv version --short)"
75+
git push
76+
git push origin "v$(uv version --short)"

docker-bake.hcl

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
variable "VERSION" {
2+
default = ""
3+
}
4+
5+
variable "LATEST_TAG" {
6+
default = "latest"
7+
}
8+
9+
variable "REGISTRY" {
10+
default = "ghcr.io/mattrobenolt/jinja2-cli"
11+
}
12+
13+
function "major" {
14+
params = [version]
15+
result = split(".", version)[0]
16+
}
17+
18+
function "minor" {
19+
params = [version]
20+
result = "${split(".", version)[0]}.${split(".", version)[1]}"
21+
}
22+
23+
function "tags" {
24+
params = [registry, version, latest_tag]
25+
result = latest_tag != "latest" ? [
26+
"${registry}:${latest_tag}"
27+
] : notequal("", version) ? [
28+
"${registry}:${version}",
29+
"${registry}:${minor(version)}",
30+
"${registry}:${major(version)}",
31+
"${registry}:${latest_tag}"
32+
] : ["${registry}:${latest_tag}"]
33+
}
34+
35+
group "default" {
36+
targets = ["jinja2-cli"]
37+
}
38+
39+
target "jinja2-cli" {
40+
context = "."
41+
dockerfile = "Dockerfile"
42+
platforms = ["linux/amd64", "linux/arm64"]
43+
tags = tags(REGISTRY, VERSION, LATEST_TAG)
44+
}

docs/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ Start here, then drill down as needed.
55
- Quickstart: [quickstart.md](quickstart.md)
66
- Formats: [formats.md](formats.md)
77
- Extensions: [extensions.md](extensions.md)
8+
- Filters: [filters.md](filters.md)
89
- Examples: [examples.md](examples.md)
10+
- Docker: [docker.md](docker.md)
911
- CLI reference: [cli.md](cli.md)
1012
- Development: [development.md](development.md)

docs/docker.md

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
# Docker
2+
3+
The official jinja2-cli Docker image is available at `ghcr.io/mattrobenolt/jinja2-cli`.
4+
5+
## Installation
6+
7+
Pull the latest image:
8+
9+
```bash
10+
docker pull ghcr.io/mattrobenolt/jinja2-cli:latest
11+
```
12+
13+
Or use a specific version:
14+
15+
```bash
16+
docker pull ghcr.io/mattrobenolt/jinja2-cli:1.0.0
17+
```
18+
19+
## Usage
20+
21+
### Basic Example
22+
23+
Mount your template and data files, then pass them as arguments:
24+
25+
```bash
26+
docker run --rm \
27+
-v $PWD:/workspace \
28+
ghcr.io/mattrobenolt/jinja2-cli:latest \
29+
/workspace/template.j2 /workspace/data.json
30+
```
31+
32+
### Using stdin
33+
34+
Pipe a template via stdin using stream mode:
35+
36+
```bash
37+
echo 'Hello {{ name }}!' | docker run --rm -i \
38+
ghcr.io/mattrobenolt/jinja2-cli:latest \
39+
-S -D name=World
40+
```
41+
42+
### With environment variables
43+
44+
Pass environment variables and access them in templates:
45+
46+
```bash
47+
docker run --rm \
48+
-v $PWD:/workspace \
49+
-e DATABASE=mysql \
50+
-e VERSION=1.0 \
51+
ghcr.io/mattrobenolt/jinja2-cli:latest \
52+
/workspace/config.j2
53+
```
54+
55+
Template:
56+
```jinja2
57+
database: {{ environ('DATABASE') }}
58+
version: {{ environ('VERSION') }}
59+
```
60+
61+
### Output to file
62+
63+
Redirect output to a file on the host:
64+
65+
```bash
66+
docker run --rm \
67+
-v $PWD:/workspace \
68+
ghcr.io/mattrobenolt/jinja2-cli:latest \
69+
/workspace/template.j2 /workspace/data.yaml --format yaml \
70+
> output.txt
71+
```
72+
73+
Or use the `-o` flag to write inside the container's filesystem:
74+
75+
```bash
76+
docker run --rm \
77+
-v $PWD:/workspace \
78+
ghcr.io/mattrobenolt/jinja2-cli:latest \
79+
/workspace/template.j2 /workspace/data.json \
80+
-o /workspace/output.txt
81+
```
82+
83+
### Multiple data files
84+
85+
Mount multiple data files and they'll be deep merged:
86+
87+
```bash
88+
docker run --rm \
89+
-v $PWD:/workspace \
90+
ghcr.io/mattrobenolt/jinja2-cli:latest \
91+
/workspace/template.j2 \
92+
/workspace/base.json \
93+
/workspace/override.yaml \
94+
/workspace/production.json
95+
```
96+
97+
## Image Details
98+
99+
- **Base**: Chainguard Wolfi (minimal, secure)
100+
- **Architectures**: `linux/amd64`, `linux/arm64`
101+
- **User**: Runs as non-root user
102+
- **Size**: ~90MB
103+
- **Includes**: All optional dependencies (yaml, toml, xml, hjson, json5)
104+
105+
## Available Tags
106+
107+
- `latest` - Latest stable release
108+
- `main` - Latest commit on main branch (development)
109+
- `1`, `1.0`, `1.0.0` - Semantic versioning tags
110+
111+
## CI/CD Usage
112+
113+
The image is useful in CI/CD pipelines for generating configuration files:
114+
115+
### GitHub Actions
116+
117+
```yaml
118+
- name: Generate config
119+
run: |
120+
docker run --rm \
121+
-v ${{ github.workspace }}:/workspace \
122+
ghcr.io/mattrobenolt/jinja2-cli:latest \
123+
/workspace/config.j2 /workspace/vars.json \
124+
-o /workspace/config.yml
125+
```
126+
127+
### GitLab CI
128+
129+
```yaml
130+
generate-config:
131+
image: ghcr.io/mattrobenolt/jinja2-cli:latest
132+
script:
133+
- jinja2 template.j2 data.json -o config.yml
134+
artifacts:
135+
paths:
136+
- config.yml
137+
```
138+
139+
## Tips
140+
141+
1. **Mount volumes** at `/workspace` or any path you prefer
142+
2. **Use absolute paths** for template and data files (e.g., `/workspace/file.j2`)
143+
3. **Stream mode** (`-S`) works great for piping templates via stdin
144+
4. **Environment variables** are accessible via `environ()` function in templates
145+
5. The image includes all optional format dependencies pre-installed

0 commit comments

Comments
 (0)