Skip to content

Commit 7bbe85f

Browse files
committed
feat(docker): add Docker image publishing to GHCR
This implementation adds automated Docker image publishing to GitHub Container Registry (ghcr.io) on every release tag. - [x] I have read the [contributing guidelines](https://commitizen-tools.github.io/commitizen/contributing/) - [ ] Add test cases to all the changes you introduce - [ ] Run `uv run poe all` locally to ensure this change passes linter check and tests - [x] Manually test the changes: - [x] Verify the feature/bug fix works as expected in real-world scenarios - [ ] Test edge cases and error conditions - [ ] Ensure backward compatibility is maintained - [x] Document any manual testing steps performed - [x] Update the documentation for the changes - [x] Run `uv run poe doc` locally to ensure the documentation pages renders correctly - [x] Check and fix any broken links (internal or external) in the documentation > When running `uv run poe doc`, any broken internal documentation links will be reported in the console output like this: > > ```text > INFO - Doc file 'config.md' contains a link 'commands/bump.md#-post_bump_hooks', but the doc 'commands/bump.md' does not contain an anchor '#-post_bump_hooks'. > ``` <!-- A clear and concise description of what you expected to happen --> The Docker image will be published at: ghcr.io/commitizen-tools/commitizen <!-- Steps to reproduce the behavior: 1. ... 2. ... 3. ... --> <!-- Add any other RELATED ISSUE, context or screenshots about the pull request here. --> Key features: - Multi-stage Dockerfile using Python 3.13 slim and UV - GitHub Actions workflow for automated publishing on v* tags - Multi-architecture support (amd64, arm64) - Multiple image tags (latest, version, major.minor, major, sha) - Build attestation for supply chain security - Documentation: new Docker tutorial and updates to existing CI guides
1 parent 5857050 commit 7bbe85f

File tree

8 files changed

+283
-1
lines changed

8 files changed

+283
-1
lines changed

.dockerignore

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Python artifacts
2+
__pycache__/
3+
*.py[cod]
4+
*$py.class
5+
*.so
6+
*.egg-info/
7+
dist/
8+
build/
9+
.eggs/
10+
*.egg
11+
12+
# Virtual environments
13+
.venv/
14+
venv/
15+
env/
16+
ENV/
17+
18+
# Testing
19+
.pytest_cache/
20+
.coverage
21+
.tox/
22+
htmlcov/
23+
junit.xml
24+
coverage.xml
25+
26+
# Git
27+
.git/
28+
.github/
29+
.gitignore
30+
31+
# IDE
32+
.vscode/
33+
.idea/
34+
*.swp
35+
*.swo
36+
37+
# Documentation
38+
docs/
39+
site/
40+
mkdocs.yml
41+
42+
# Misc
43+
*.md
44+
LICENSE
45+
.DS_Store
46+
.ruff_cache/
47+
.mypy_cache/
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
name: Publish Docker Image
2+
3+
on:
4+
push:
5+
tags:
6+
- "v*"
7+
8+
env:
9+
REGISTRY: ghcr.io
10+
IMAGE_NAME: ${{ github.repository }}
11+
12+
jobs:
13+
build-and-push:
14+
runs-on: ubuntu-latest
15+
permissions:
16+
contents: read
17+
packages: write
18+
attestations: write
19+
id-token: write
20+
21+
steps:
22+
- name: Checkout repository
23+
uses: actions/checkout@v6
24+
25+
- name: Set up Docker Buildx
26+
uses: docker/setup-buildx-action@v3
27+
28+
- name: Log in to GitHub Container Registry
29+
uses: docker/login-action@v3
30+
with:
31+
registry: ${{ env.REGISTRY }}
32+
username: ${{ github.actor }}
33+
password: ${{ secrets.GITHUB_TOKEN }}
34+
35+
- name: Extract version from tag
36+
id: version
37+
run: |
38+
# Remove 'v' prefix from tag (v4.12.1 -> 4.12.1)
39+
VERSION=${GITHUB_REF_NAME#v}
40+
echo "version=${VERSION}" >> $GITHUB_OUTPUT
41+
echo "Version: ${VERSION}"
42+
43+
- name: Extract metadata for Docker
44+
id: meta
45+
uses: docker/metadata-action@v5
46+
with:
47+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
48+
tags: |
49+
# Full version tag (e.g. 4.12.1)
50+
type=semver,pattern={{version}}
51+
# Version tag with v prefix (e.g. v4.12.1)
52+
type=semver,pattern=v{{version}}
53+
# Major.minor tag (e.g. 4.12)
54+
type=semver,pattern={{major}}.{{minor}}
55+
# Major version tag (e.g. 4)
56+
type=semver,pattern={{major}}
57+
# Always tag as latest
58+
type=raw,value=latest
59+
# SHA tag for debugging (e.g. sha-abc1234)
60+
type=sha,prefix=sha-
61+
labels: |
62+
org.opencontainers.image.title=Commitizen
63+
org.opencontainers.image.description=Python commitizen client tool - release management for teams
64+
org.opencontainers.image.vendor=Commitizen Tools
65+
66+
- name: Build and push Docker image
67+
id: push
68+
uses: docker/build-push-action@v6
69+
with:
70+
context: .
71+
push: true
72+
tags: ${{ steps.meta.outputs.tags }}
73+
labels: ${{ steps.meta.outputs.labels }}
74+
build-args: |
75+
CZ_VERSION=${{ steps.version.outputs.version }}
76+
cache-from: type=gha
77+
cache-to: type=gha,mode=max
78+
platforms: linux/amd64,linux/arm64
79+
80+
- name: Generate artifact attestation
81+
uses: actions/attest-build-provenance@v2
82+
with:
83+
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
84+
subject-digest: ${{ steps.push.outputs.digest }}
85+
push-to-registry: true

.github/workflows/pythonpackage.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,40 @@ jobs:
6868
with:
6969
token: ${{ secrets.CODECOV_TOKEN }}
7070
report_type: test_results
71+
72+
docker-build-test:
73+
runs-on: ubuntu-latest
74+
steps:
75+
- uses: actions/checkout@v6
76+
77+
- name: Check for Dockerfile changes
78+
uses: dorny/paths-filter@v3
79+
id: filter
80+
with:
81+
filters: |
82+
docker:
83+
- 'Dockerfile'
84+
- '.dockerignore'
85+
- '.github/workflows/dockerpublish.yml'
86+
87+
- name: Extract version from pyproject.toml
88+
if: steps.filter.outputs.docker == 'true'
89+
id: version
90+
run: |
91+
VERSION=$(grep '^version = ' pyproject.toml | cut -d'"' -f2)
92+
echo "version=${VERSION}" >> $GITHUB_OUTPUT
93+
echo "Testing with version: ${VERSION}"
94+
95+
- name: Set up Docker Buildx
96+
if: steps.filter.outputs.docker == 'true'
97+
uses: docker/setup-buildx-action@v3
98+
99+
- name: Test Docker build
100+
if: steps.filter.outputs.docker == 'true'
101+
uses: docker/build-push-action@v6
102+
with:
103+
context: .
104+
push: false
105+
build-args: |
106+
CZ_VERSION=${{ steps.version.outputs.version }}
107+
cache-from: type=gha

Dockerfile

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
FROM python:3.13-slim AS builder
2+
3+
WORKDIR /app
4+
5+
# Installer UV pour une installation rapide des dépendances
6+
RUN pip install --no-cache-dir uv
7+
8+
# Argument de build pour la version (passé depuis GitHub Actions)
9+
ARG CZ_VERSION
10+
RUN test -n "$CZ_VERSION" || (echo "CZ_VERSION not set" && false)
11+
12+
# Installer commitizen avec UV
13+
RUN uv pip install --system --no-cache commitizen==${CZ_VERSION}
14+
15+
# Stage runtime
16+
FROM python:3.13-slim
17+
18+
LABEL org.opencontainers.image.source="https://github.com/commitizen-tools/commitizen"
19+
LABEL org.opencontainers.image.description="Commitizen is a release management tool designed for teams"
20+
LABEL org.opencontainers.image.licenses="MIT"
21+
22+
# Installer git (requis pour le fonctionnement de commitizen)
23+
RUN apt-get update && \
24+
apt-get install -y --no-install-recommends git && \
25+
rm -rf /var/lib/apt/lists/*
26+
27+
# Copier les packages Python et binaires depuis le builder
28+
COPY --from=builder /usr/local/lib/python3.13/site-packages /usr/local/lib/python3.13/site-packages
29+
COPY --from=builder /usr/local/bin/cz /usr/local/bin/cz
30+
COPY --from=builder /usr/local/bin/git-cz /usr/local/bin/git-cz
31+
32+
# Répertoire de travail
33+
WORKDIR /workspace
34+
35+
# Point d'entrée sur la commande cz
36+
ENTRYPOINT ["cz"]
37+
38+
# Commande par défaut : afficher la version
39+
CMD ["version"]

docs/README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,20 @@ uv tool upgrade commitizen
8888
brew install commitizen
8989
```
9090

91+
#### Docker Installation
92+
93+
If you prefer using Docker or don't have Python installed:
94+
95+
```bash
96+
# Pull the latest image
97+
docker pull ghcr.io/commitizen-tools/commitizen:latest
98+
99+
# Use as a command
100+
docker run -v $(pwd):/workspace ghcr.io/commitizen-tools/commitizen:latest --help
101+
```
102+
103+
For detailed Docker usage, see the [Docker tutorial](https://commitizen-tools.github.io/commitizen/tutorials/docker/).
104+
91105
#### Project-Specific Installation
92106

93107
You can add Commitizen to your Python project using any of these package managers:
@@ -240,6 +254,7 @@ Commitizen provides a comprehensive CLI with various commands. Here's the comple
240254
- [Exit Codes Reference](https://commitizen-tools.github.io/commitizen/exit_codes/)
241255
- [Configuration Guide](https://commitizen-tools.github.io/commitizen/config/configuration_file/)
242256
- [Command Documentation](https://commitizen-tools.github.io/commitizen/commands/init/)
257+
- [Docker Usage Guide](https://commitizen-tools.github.io/commitizen/tutorials/docker/)
243258
244259
### Getting Help
245260

docs/tutorials/docker.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Using Commitizen with Docker
2+
3+
Commitizen provides official Docker images hosted on GitHub Container Registry (GHCR), making it easy to use Commitizen in containerized environments without needing Python or pip installed on your host machine.
4+
5+
## Quick Start
6+
7+
### Pull the Latest Image
8+
9+
```bash
10+
docker pull ghcr.io/commitizen-tools/commitizen:latest
11+
```
12+
13+
### Basic Usage
14+
15+
```bash
16+
# Check version
17+
docker run ghcr.io/commitizen-tools/commitizen:latest version
18+
19+
# Get help
20+
docker run ghcr.io/commitizen-tools/commitizen:latest --help
21+
22+
# Use with a git repository
23+
docker run -v $(pwd):/workspace ghcr.io/commitizen-tools/commitizen:latest check
24+
```
25+
26+
## Image Details
27+
28+
### Base Image
29+
30+
- **Base**: Python 3.13 slim (Debian)
31+
- **Architecture**: Multi-arch (amd64, arm64)
32+
- **Size**: Optimized with multi-stage build
33+
34+
### Included Tools
35+
36+
- Python 3.13
37+
- Commitizen (from PyPI)
38+
- Git (required for Commitizen operations)
39+
40+
### Entry Point
41+
42+
The container entry point is set to `cz`, so you can pass commands directly:
43+
44+
```bash
45+
# These are equivalent:
46+
docker run ghcr.io/commitizen-tools/commitizen:latest version
47+
docker run --entrypoint cz ghcr.io/commitizen-tools/commitizen:latest version
48+
```

docs/tutorials/gitlab_ci.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,17 @@ For this example, we have a `python/django` application and `Docker` as a contai
44

55
_Goal_: Bump a new version every time that a change occurs on the `master` branch. The bump should be executed automatically by the `CI` process.
66

7+
!!! tip "Using Docker"
8+
Instead of installing Commitizen with pip, you can use the official Docker image:
9+
```yaml
10+
auto-bump:
11+
stage: auto-bump
12+
image: ghcr.io/commitizen-tools/commitizen:latest
13+
script:
14+
- cz bump --yes
15+
```
16+
See the [Docker tutorial](docker.md) for more details.
17+
718
### Development Workflow
819

920
1. A developer creates a new commit on any branch (except `master`)

docs/tutorials/jenkins_pipeline.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pipeline {
3434
}
3535
}
3636
37-
def useCz(String authorName = 'Jenkins CI Server', String authorEmail = 'your-jenkins@email.com', String image = 'registry.hub.docker.com/commitizen/commitizen:latest', Closure body) {
37+
def useCz(String authorName = 'Jenkins CI Server', String authorEmail = 'your-jenkins@email.com', String image = 'ghcr.io/commitizen-tools/commitizen:latest', Closure body) {
3838
docker
3939
.image(image)
4040
.inside("-u 0 -v $WORKSPACE:/workspace -w /workspace -e GIT_AUTHOR_NAME='${authorName}' -e GIT_AUTHOR_EMAIL='${authorEmail}' -entrypoint='/bin/sh'") {

0 commit comments

Comments
 (0)