Skip to content

Commit 830e87a

Browse files
committed
ci: add GitHub Actions build release workflow
Builds the service image locally, packages configuration alongside the image, and publishes a GitHub release asset for download.
1 parent 63f561d commit 830e87a

4 files changed

Lines changed: 230 additions & 0 deletions

File tree

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
---
2+
name: Build Release
3+
4+
'on':
5+
push:
6+
branches:
7+
- "**"
8+
workflow_dispatch:
9+
10+
permissions:
11+
contents: write
12+
pull-requests: read
13+
14+
jobs:
15+
detect-project-changes:
16+
name: Check for new version
17+
runs-on: ubuntu-latest
18+
outputs:
19+
changed: ${{ steps.check.outputs.changed }}
20+
steps:
21+
- uses: actions/checkout@v5
22+
with:
23+
fetch-depth: 0
24+
25+
- name: Check if pyproject.toml changed
26+
id: check
27+
shell: bash
28+
run: |
29+
if git rev-parse HEAD^ >/dev/null 2>&1; then
30+
CHANGED_FILES="$(git diff --name-only HEAD^ HEAD)"
31+
else
32+
echo "No parent commit found, using full file list"
33+
CHANGED_FILES="$(git ls-files)"
34+
fi
35+
36+
echo "Changed files:"
37+
echo "$CHANGED_FILES"
38+
39+
if echo "$CHANGED_FILES" | grep -q '^pyproject\.toml$'; then
40+
echo "pyproject.toml changed, marking as changed"
41+
echo "changed=true" >> "$GITHUB_OUTPUT"
42+
else
43+
echo "pyproject.toml not changed, skipping release"
44+
echo "changed=false" >> "$GITHUB_OUTPUT"
45+
fi
46+
47+
run-tests:
48+
name: Run Tests
49+
runs-on: ubuntu-latest
50+
51+
steps:
52+
- name: Checkout code
53+
uses: actions/checkout@v5
54+
55+
- name: Set up Python
56+
uses: actions/setup-python@v5
57+
with:
58+
python-version: "3.11"
59+
60+
- name: Install dependencies
61+
run: |
62+
python -m pip install --upgrade pip
63+
python -m pip install .
64+
python -m pip install pytest pytest-asyncio pytest-mock pytest-cov
65+
66+
- name: Run tests
67+
run: pytest -v tests
68+
69+
docker-release:
70+
name: Build Local Docker Image and Release Bundle
71+
needs: [detect-project-changes, run-tests]
72+
if: >-
73+
github.ref == 'refs/heads/main' &&
74+
needs.detect-project-changes.outputs.changed == 'true'
75+
runs-on: ubuntu-latest
76+
77+
steps:
78+
- name: Checkout code
79+
uses: actions/checkout@v5
80+
with:
81+
fetch-depth: 0
82+
83+
- name: Set up Python
84+
uses: actions/setup-python@v5
85+
with:
86+
python-version: "3.11"
87+
88+
- name: Extract version and commit hash
89+
id: meta
90+
shell: bash
91+
run: |
92+
VERSION=$(python - <<'PY'
93+
import tomllib
94+
95+
with open('pyproject.toml', 'rb') as file_handle:
96+
print(tomllib.load(file_handle)['project']['version'])
97+
PY
98+
)
99+
GIT_HASH=$(git rev-parse --short HEAD)
100+
101+
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
102+
echo "hash=$GIT_HASH" >> "$GITHUB_OUTPUT"
103+
104+
- name: Build Docker image
105+
shell: bash
106+
env:
107+
IMAGE_TAG: ${{ steps.meta.outputs.image_tag }}
108+
run: |
109+
docker build \
110+
--tag "$IMAGE_TAG" \
111+
--tag "ms-database-connector:latest" \
112+
.
113+
114+
- name: Create release bundle
115+
shell: bash
116+
env:
117+
IMAGE_TAG: ${{ steps.meta.outputs.image_tag }}
118+
ARTIFACT_NAME: ${{ steps.meta.outputs.artifact_name }}
119+
run: |
120+
mkdir -p dist/release-bundle
121+
docker save "$IMAGE_TAG" -o dist/release-bundle/image.tar
122+
cp -R configuration dist/release-bundle/configuration
123+
124+
cat > dist/release-bundle/README.txt <<EOF
125+
This bundle contains the Docker image tarball and the
126+
configuration directory.
127+
128+
Usage:
129+
docker load -i image.tar
130+
docker run --rm -p 3090:3090 \
131+
-e DBC_CONFIGURATION_FILE=/app/configuration/service_config.json \
132+
"$IMAGE_TAG"
133+
134+
If you want to mount the configuration from the extracted bundle
135+
instead of using the copy baked into the image, run the container
136+
with:
137+
-v "./configuration:/app/configuration"
138+
EOF
139+
140+
tar -czf "$ARTIFACT_NAME" -C dist/release-bundle .
141+
142+
- name: Create Git Tag
143+
shell: bash
144+
run: |
145+
VERSION_TAG="v${{ steps.meta.outputs.version }}"
146+
if git rev-parse "$VERSION_TAG" >/dev/null 2>&1; then
147+
echo "Tag $VERSION_TAG already exists."
148+
else
149+
git tag "$VERSION_TAG"
150+
git push origin "$VERSION_TAG"
151+
fi
152+
153+
- name: Create GitHub Release
154+
uses: softprops/action-gh-release@v3
155+
with:
156+
tag_name: v${{ steps.meta.outputs.version }}
157+
name: Release v${{ steps.meta.outputs.version }}
158+
generate_release_notes: true
159+
files: |
160+
dist/release.tar.gz
161+
body: |
162+
Download the attached release archive to get the Docker image
163+
tarball and the configuration directory side by side.
164+
165+
Local usage:
166+
167+
```bash
168+
tar -xzf release.tar.gz
169+
docker load -i image.tar
170+
IMAGE_TAG=ms-database-connector:0.0.1-<git-hash>
171+
docker run --rm -p 3090:3090 \
172+
-e DBC_CONFIGURATION_FILE=/app/configuration/service_config.json \
173+
"$IMAGE_TAG"
174+
```
175+
env:
176+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Dockerfile

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
FROM python:3.11-slim
2+
3+
ENV PYTHONDONTWRITEBYTECODE=1 \
4+
PYTHONUNBUFFERED=1 \
5+
APP_HOST=0.0.0.0 \
6+
APP_PORT=3090 \
7+
RUN_SERVER=1 \
8+
DBC_CONFIGURATION_FILE=/app/configuration/service_config.json
9+
10+
WORKDIR /app
11+
12+
COPY pyproject.toml README.md LICENSE ./
13+
COPY ms_database_connector ./ms_database_connector
14+
15+
RUN python -m pip install --upgrade pip && \
16+
python -m pip install --no-cache-dir .
17+
18+
COPY configuration ./configuration
19+
20+
EXPOSE 3090
21+
22+
CMD ["python", "-m", "ms_database_connector"]

README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,31 @@ When you run this service (default: `APP_HOST=127.0.0.1`, `APP_PORT=3088`), thes
3737
- http://127.0.0.1:3088/health
3838
- http://127.0.0.1:3088/aas/shells
3939
- http://127.0.0.1:3088/aas/registry
40+
41+
### GitHub Release Bundle
42+
43+
The GitHub Actions workflow builds a local Docker image and uploads a portable release bundle.
44+
45+
The bundle contains:
46+
47+
- `image.tar` for `docker load`
48+
- the `configuration/` directory next to it
49+
- a short usage note
50+
51+
Typical local usage after downloading and extracting the bundle:
52+
53+
```bash
54+
docker load -i image.tar
55+
docker run --rm -p 3090:3090 \
56+
-e DBC_CONFIGURATION_FILE=/app/configuration/service_config.json \
57+
ms-database-connector:0.0.1-<git-hash>
58+
```
59+
60+
If you want to override the bundled configuration with a local directory, mount it into the container:
61+
62+
```bash
63+
docker run --rm -p 3090:3090 \
64+
-v "$(pwd)/configuration:/app/configuration" \
65+
-e DBC_CONFIGURATION_FILE=/app/configuration/service_config.json \
66+
ms-database-connector:0.0.1-<git-hash>
67+
```

pyproject.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ classifiers = [
1515
"Operating System :: OS Independent",
1616
]
1717

18+
[build-system]
19+
requires = ["poetry-core>=1.9.0"]
20+
build-backend = "poetry.core.masonry.api"
21+
1822
# Missing library stubs or py.typed marker files are ignored to avoid mypy errors.
1923
[[tool.mypy.overrides]]
2024
module = ["influxdb.*", "aas_http_client", "aas_http_client.*"]

0 commit comments

Comments
 (0)