Skip to content

Commit deef68f

Browse files
authored
Build a docker image (#35)
* add rich to the dependencies, ... use rich.print() to add some colour to the output and finally add a test for it * fix the test workflow * add Dockerfile, dockerignore * improve the README, add a docker section * add docker-publish action
1 parent e0fec85 commit deef68f

File tree

9 files changed

+249
-29
lines changed

9 files changed

+249
-29
lines changed

.dockerignore

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
.git/
2+
.gitignore
3+
4+
build
5+
dist
6+
*.egg-info
7+
*.egg/
8+
*.pyc
9+
*.swp
10+
11+
.tox
12+
.coverage
13+
html/*
14+
__pycache__
15+
*/__pycache__
16+
17+
.pytest_cache/
18+
*/.pytest_cache/
19+
20+
.vagrant/
21+
*-vagrant-up.log
22+
23+
.with_*
24+
.idea/
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: "Build and publish image to GitHub Packages"
2+
3+
on:
4+
push:
5+
branches: [ "main" ]
6+
release:
7+
types: [published, released]
8+
workflow_dispatch:
9+
10+
env:
11+
REGISTRY: ghcr.io
12+
IMAGE_NAME: ${{ github.repository }}
13+
14+
jobs:
15+
build-and-push-image:
16+
runs-on: ubuntu-latest
17+
permissions:
18+
contents: read
19+
packages: write
20+
21+
steps:
22+
- name: Checkout repository
23+
uses: actions/checkout@v4
24+
25+
- name: Log in to the Container registry
26+
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
27+
with:
28+
registry: ${{ env.REGISTRY }}
29+
username: ${{ github.actor }}
30+
password: ${{ secrets.GITHUB_TOKEN }}
31+
32+
- name: Extract metadata (tags, labels) for Docker
33+
id: meta
34+
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
35+
with:
36+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
37+
38+
- name: Build and push Docker image
39+
uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4
40+
with:
41+
context: .
42+
push: true
43+
tags: "${{ steps.meta.outputs.tags }}, ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest, ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}"
44+
labels: ${{ steps.meta.outputs.labels }}

.github/workflows/python-run-tests.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,6 @@ jobs:
7272
- name: Test with pytest
7373
run: |
7474
export PYTHONPATH=$PYTHONPATH:.
75+
# make sure pytest will use color in terminal output
76+
export FORCE_COLOR="true"
7577
$POETRY_HOME/bin/poetry run pytest

Dockerfile

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# syntax=docker/dockerfile:1
2+
3+
# base
4+
FROM python:3.12-slim-bookworm AS base
5+
ARG POETRY_VERSION="1.8.3"
6+
RUN adduser --disabled-login --gecos "" user
7+
USER user
8+
ENV PATH="${PATH}:/home/user/.local/bin/"
9+
WORKDIR /usr/src/app
10+
ENV POETRY_VERSION=${POETRY_VERSION}
11+
RUN pip install --upgrade setuptools pip && \
12+
pip install --upgrade poetry==${POETRY_VERSION}
13+
COPY --chown=user:user application application/
14+
COPY --chown=user:user data data/
15+
COPY --chown=user:user poetry.lock pyproject.toml ./
16+
17+
# test
18+
FROM base AS test
19+
USER user
20+
ENV PATH="${PATH}:/home/user/.local/bin/"
21+
WORKDIR /usr/src/app
22+
RUN poetry install --with test --no-root
23+
ENV PYTHONPATH="${PYTHONPATH}:/user/src/app"
24+
COPY --chown=user:user test test/
25+
# make sure pytest will use color in terminal output
26+
ENV FORCE_COLOR="true"
27+
CMD ["poetry", "run", "pytest"]
28+
29+
# dev
30+
FROM test AS dev
31+
USER root
32+
RUN apt-get update && \
33+
apt-get install git vim -y
34+
USER user
35+
ENV PATH="${PATH}:/home/user/.local/bin/"
36+
WORKDIR /usr/src/app
37+
COPY --chown=user:user .pre-commit-config.yaml ./
38+
RUN poetry install --with test,dev --no-root
39+
RUN git init . && \
40+
poetry run pre-commit --version && \
41+
poetry run pre-commit install
42+
ENV PYTHONPATH="${PYTHONPATH}:/user/src/app"
43+
CMD ["/bin/bash"]
44+
45+
# run
46+
FROM base AS run
47+
USER user
48+
ENV PATH="${PATH}:/home/user/.local/bin/"
49+
WORKDIR /usr/src/app
50+
RUN poetry install --only main --no-root
51+
ENV PYTHONPATH="${PYTHONPATH}:/user/src/app"
52+
CMD ["poetry", "run", "python", "application/main.py"]

README.md

Lines changed: 54 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,24 @@
33
Simple template for Python `3.12` with `pyenv`/`pyenv-virtualenv` and `poetry`.
44

55
- [quickstart](#quickstart)
6-
- [pyenv/pyenv-virtualenv](#pyenvpyenv-virtualenv)
7-
- [poetry](#poetry)
6+
- [pyenv/pyenv-virtualenv](#pyenvpyenv-virtualenv)
7+
- [poetry](#poetry)
8+
- [pre-comit](#pre-commit)
9+
- [docker](#docker)
810
- [vagrant](#vagrant)
911
- [reference](#reference)
1012

1113
## quickstart
1214

13-
- clone the repo
14-
```shell
15-
git clone git@github.com:markgreene74/python-template.git
16-
```
15+
### clone the repo
1716

18-
## pyenv/pyenv-virtualenv
17+
```shell
18+
git clone git@github.com:markgreene74/python-template.git
19+
```
1920

20-
TODO
21-
- make sure `pyenv` is installed
22-
- make sure `pyenv-virtualenv` is installed
21+
### pyenv/pyenv-virtualenv
22+
23+
- make sure `pyenv` and `pyenv-virtualenv` are installed
2324
- install python `3.12`, for example `3.12.3`
2425
```bash
2526
pyenv install 3.12.3
@@ -37,34 +38,60 @@ TODO
3738
pip install --upgrade pip setuptools
3839
```
3940

40-
## poetry
41+
### poetry
4142

4243
- install poetry
4344
```bash
4445
pip install --upgrade poetry==1.8.3
4546
```
46-
- install the application runtime dependencies
47-
```bash
48-
poetry install --only main
49-
```
50-
- install the application test dependencies
47+
- to install
48+
- the application runtime dependencies
49+
```bash
50+
poetry install --only main
51+
```
52+
- the application test dependencies
53+
```bash
54+
poetry install --with test
55+
```
56+
- the application dev and test dependencies
57+
```bash
58+
poetry install --with test,dev
59+
```
60+
- the dependencies but not the current project
61+
```bash
62+
poetry install --no-root --with test,dev
63+
```
64+
65+
### pre-commit
66+
67+
This project uses [`pre-commit`](https://pre-commit.com/).
68+
69+
- install the hooks from the `.pre-commit-config.yaml` file
5170
```bash
52-
poetry install --with test
71+
pre-commit install
5372
```
54-
- install the application dev, test dependencies
55-
```bash
56-
poetry install --with test,dev
73+
74+
## docker
75+
76+
- build the image
77+
```shell
78+
docker build -t python-template .
5779
```
58-
- install the dependencies but not the current project
59-
```bash
60-
poetry install --no-root --with test,dev
80+
- run the container
81+
```shell
82+
docker run -it --rm python-template
6183
```
6284

63-
## pre-commit
64-
65-
This project use `pre-commit`. A `.pre-commit-config.yaml` is included.
85+
Intermediate stages (`test`, `dev`) are available in the `Dockerfile`. Build them with:
86+
```shell
87+
docker build -t python-template . --target <stage>
88+
```
6689

67-
Run `pre-commit install` to install the Git hooks.
90+
For example, build and tun the tests with:
91+
```shell
92+
docker build -t python-template . --target test && \
93+
docker run -it --rm python-template
94+
```
6895

6996
## vagrant
7097

application/main.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import datetime as dt
22

3+
from rich import print as rp
4+
35
import application.helpers.helpers_main as hlp_m
46

57
# variables
@@ -8,7 +10,7 @@
810
# main function goes here
911
def main() -> dt.datetime:
1012
_now = hlp_m.get_timestamp()
11-
print(f"The current datetime is: {_now}")
13+
rp(f"The current datetime is: [bold magenta]{_now}[/bold magenta]")
1214

1315
# just return the timestamp for now, so we have something to test
1416
return _now

poetry.lock

Lines changed: 68 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ readme = "README.md"
88

99
[tool.poetry.dependencies]
1010
python = "^3.12"
11+
rich = "^13.9.2"
1112

1213

1314
[tool.poetry.group.test.dependencies]

test/test_main.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ def test_main_output(capsys):
1616
main.main()
1717
out, err = capsys.readouterr()
1818
assert MAIN_MSG in out
19+
assert "\x1b[1;35m" in out # the output contains colours
1920
assert err == ""

0 commit comments

Comments
 (0)