Compare commits

...

2 Commits

Author SHA1 Message Date
Christian Merten 3e5f6f0d27
chore: update favicon 1 month ago
Christian Merten 461cb098f0
chore(ci): build and release docker image, build documentation (#7)
We expand the tests CI run to first build the main image, build and
deploy the documentation pages, run the test suite and publish the
docker image in the github docker registry.
2 months ago

@ -0,0 +1,147 @@
name: Build and test
on:
push:
branches:
- main
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
REGISTRY: ghcr.io
APP_IMAGE_NAME: ${{ github.repository }}
NGINX_IMAGE_NAME: ${{ github.repository }}-nginx
jobs:
build-test-and-deploy:
runs-on: ubuntu-latest
permissions:
contents: write
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: recursive
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata for application image
id: meta-app
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.APP_IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=sha,prefix={{branch}}-
type=raw,value=latest,enable={{is_default_branch}}
- name: Extract metadata for nginx image
id: meta-nginx
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.NGINX_IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=sha,prefix={{branch}}-
type=raw,value=latest,enable={{is_default_branch}}
- name: Build application image
uses: docker/build-push-action@v5
with:
context: .
file: docker/production/Dockerfile
load: true
tags: kompass:test
cache-from: |
type=gha,scope=app-${{ github.ref_name }}
type=gha,scope=app-master
type=gha,scope=app-main
type=registry,ref=ghcr.io/${{ github.repository }}:latest
cache-to: type=gha,mode=max,scope=app-${{ github.ref_name }}
build-args: |
BUILDKIT_INLINE_CACHE=1
- name: Build documentation
run: |
# Create output directory with proper permissions
mkdir -p docs-output
chmod 777 docs-output
# Run sphinx-build inside the container
docker run --rm \
-v ${{ github.workspace }}/docs:/app/docs:ro \
-v ${{ github.workspace }}/docs-output:/app/docs-output \
kompass:test \
bash -c "cd /app/docs && sphinx-build -b html source /app/docs-output"
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./docs-output
destination_dir: ${{ github.ref == 'refs/heads/main' && '.' || github.ref_name }}
keep_files: true
- name: Run tests
run: make test-only
- name: Check coverage
run: |
COVERAGE=$(python3 -c "import json; data=json.load(open('docker/test/htmlcov/coverage.json')); print(data['totals']['percent_covered'])")
echo "Coverage: ${COVERAGE}%"
if (( $(echo "$COVERAGE < 100" | bc -l) )); then
echo "Error: Coverage is ${COVERAGE}%, must be 100%"
exit 1
fi
- name: Tag and push application image
if: github.event_name != 'pull_request'
run: |
# Tag the built image with all required tags
echo "${{ steps.meta-app.outputs.tags }}" | while read -r tag; do
docker tag kompass:test "$tag"
docker push "$tag"
done
- name: Build and push nginx image
if: github.event_name != 'pull_request'
uses: docker/build-push-action@v5
with:
context: docker/production/nginx
file: docker/production/nginx/Dockerfile
push: true
tags: ${{ steps.meta-nginx.outputs.tags }}
labels: ${{ steps.meta-nginx.outputs.labels }}
cache-from: |
type=gha,scope=nginx-${{ github.ref_name }}
type=gha,scope=nginx-master
type=gha,scope=nginx-main
type=registry,ref=ghcr.io/${{ github.repository }}-nginx:latest
cache-to: type=gha,mode=max,scope=nginx-${{ github.ref_name }}
build-args: |
BUILDKIT_INLINE_CACHE=1
- name: Output image tags
if: github.event_name != 'pull_request'
run: |
echo "Application image tags:"
echo "${{ steps.meta-app.outputs.tags }}"
echo ""
echo "Nginx image tags:"
echo "${{ steps.meta-nginx.outputs.tags }}"

@ -1,60 +0,0 @@
name: Tests
on:
push:
branches:
- main
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Cache Docker layers
uses: actions/cache@v4
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ hashFiles('requirements.txt', 'docker/test/Dockerfile') }}
restore-keys: |
${{ runner.os }}-buildx-
- name: Build Docker image with cache
run: |
cd docker/test
docker buildx build \
--cache-from type=local,src=/tmp/.buildx-cache \
--cache-to type=local,dest=/tmp/.buildx-cache-new,mode=max \
--load \
-t kompass:test \
-f Dockerfile \
../../
- name: Move cache
run: |
rm -rf /tmp/.buildx-cache
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
- name: Run tests
run: make test-only
- name: Check coverage
run: |
COVERAGE=$(python3 -c "import json; data=json.load(open('docker/test/htmlcov/coverage.json')); print(data['totals']['percent_covered'])")
echo "Coverage: ${COVERAGE}%"
if (( $(echo "$COVERAGE < 100" | bc -l) )); then
echo "Error: Coverage is ${COVERAGE}%, must be 100%"
exit 1
fi

@ -1,6 +1,6 @@
# jdav Kompass
![Build Status](https://github.com/chrisflav/kompass/actions/workflows/test.yml/badge.svg?branch=main)
![Build Status](https://github.com/chrisflav/kompass/actions/workflows/build-docker.yml/badge.svg?branch=main)
Kompass is an administration platform designed for local sections of the Young German Alpine Club. It provides
tools to contact and (automatically) manage members, groups, material, excursions and statements.

@ -22,8 +22,6 @@ ENV PATH="/app/.local/bin:$PATH"
# install requirements
COPY --chown=app:app ./requirements.txt /app/requirements.txt
# we install uwsgi here to check if packages dependencies are resolved, but we don't actually
# need uwsgi in test
RUN pip install coverage uwsgi -r requirements.txt
RUN pip install uwsgi -r requirements.txt
COPY --chown=app:app . /app

@ -1 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"><defs><style>.c{fill:#9cc;}.d{fill:#2d5955;}.e{stroke:#2d5955;stroke-width:3.2px;}.e,.f{fill:none;stroke-miterlimit:10;}.g{fill:#666;mix-blend-mode:multiply;}.f{stroke:#666;stroke-width:3.3px;}.h{opacity:.36;}.i{isolation:isolate;}.j{fill:#fff;opacity:.24;}</style></defs><g class="i"><g id="a"><circle class="f" cx="24.31" cy="24.31" r="21.69"/></g><g id="b"><circle class="e" cx="23.69" cy="23.69" r="21.69"/><polygon class="g" points="21.2 22.96 15.21 43.89 27.68 25.98 33.66 5.05 21.2 22.96"/><polygon class="c" points="14.34 43.15 26.8 25.24 20.32 22.23 14.34 43.15"/><polygon class="d" points="32.79 4.32 20.32 22.23 26.8 25.24 32.79 4.32"/><polyline class="h" points="14.34 43.15 26.8 25.24 32.79 4.32"/><circle class="j" cx="23.61" cy="23.64" r="1.55"/></g></g></svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 27.3.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 48 48" style="enable-background:new 0 0 48 48;" xml:space="preserve">
<style type="text/css">
.st0{display:none;}
.st1{display:inline;fill:#254D49;}
.st2{display:inline;opacity:0.27;fill:url(#SVGID_1_);}
.st3{fill:none;stroke:#1B2E2C;stroke-width:3;stroke-miterlimit:10;}
.st4{fill:#1B2E2C;}
.st5{fill:none;stroke:#508480;stroke-width:3.2;stroke-miterlimit:10;}
.st6{fill:#BADDD9;}
.st7{fill:#508480;}
.st8{opacity:0.36;}
.st9{opacity:0.24;fill:#FFFFFF;}
</style>
<g id="Hintergrund_x5F_Uni" class="st0">
<rect class="st1" width="48" height="48"/>
</g>
<g id="Verlauf" class="st0">
<radialGradient id="SVGID_1_" cx="23.348" cy="21.0566" r="25.4002" fx="3.9002" fy="4.7179" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#000000;stop-opacity:0"/>
<stop offset="1" style="stop-color:#000000"/>
</radialGradient>
<circle class="st2" cx="23.6" cy="23.6" r="22.9"/>
</g>
<g id="Logo_x5F_Schatten">
<circle class="st3" cx="24.3" cy="24.3" r="21.7"/>
<polygon class="st4" points="21.4,22.9 15.8,42.4 27.5,25.7 33.2,6.2 "/>
</g>
<g id="LogooVordergrund">
<circle class="st5" cx="23.7" cy="23.7" r="21.7"/>
<g>
<polygon class="st6" points="14.9,41.8 26.6,25.1 20.5,22.2 "/>
<polygon class="st7" points="32.3,5.5 20.5,22.2 26.6,25.1 "/>
<polyline class="st8" points="14.9,41.8 26.6,25.1 32.3,5.5 "/>
<circle class="st9" cx="23.6" cy="23.6" r="1.6"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 873 B

After

Width:  |  Height:  |  Size: 1.6 KiB

@ -1 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"><defs><style>.c{fill:#9cc;}.d{fill:#2d5955;}.e{stroke:#2d5955;stroke-width:3.2px;}.e,.f{fill:none;stroke-miterlimit:10;}.g{fill:#666;mix-blend-mode:multiply;}.f{stroke:#666;stroke-width:3.3px;}.h{opacity:.36;}.i{isolation:isolate;}.j{fill:#fff;opacity:.24;}</style></defs><g class="i"><g id="a"><circle class="f" cx="24.31" cy="24.31" r="21.69"/></g><g id="b"><circle class="e" cx="23.69" cy="23.69" r="21.69"/><polygon class="g" points="21.2 22.96 15.21 43.89 27.68 25.98 33.66 5.05 21.2 22.96"/><polygon class="c" points="14.34 43.15 26.8 25.24 20.32 22.23 14.34 43.15"/><polygon class="d" points="32.79 4.32 20.32 22.23 26.8 25.24 32.79 4.32"/><polyline class="h" points="14.34 43.15 26.8 25.24 32.79 4.32"/><circle class="j" cx="23.61" cy="23.64" r="1.55"/></g></g></svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 27.3.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 48 48" style="enable-background:new 0 0 48 48;" xml:space="preserve">
<style type="text/css">
.st0{display:none;}
.st1{display:inline;fill:#254D49;}
.st2{display:inline;opacity:0.27;fill:url(#SVGID_1_);}
.st3{fill:none;stroke:#1B2E2C;stroke-width:3;stroke-miterlimit:10;}
.st4{fill:#1B2E2C;}
.st5{fill:none;stroke:#508480;stroke-width:3.2;stroke-miterlimit:10;}
.st6{fill:#BADDD9;}
.st7{fill:#508480;}
.st8{opacity:0.36;}
.st9{opacity:0.24;fill:#FFFFFF;}
</style>
<g id="Hintergrund_x5F_Uni" class="st0">
<rect class="st1" width="48" height="48"/>
</g>
<g id="Verlauf" class="st0">
<radialGradient id="SVGID_1_" cx="23.348" cy="21.0566" r="25.4002" fx="3.9002" fy="4.7179" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#000000;stop-opacity:0"/>
<stop offset="1" style="stop-color:#000000"/>
</radialGradient>
<circle class="st2" cx="23.6" cy="23.6" r="22.9"/>
</g>
<g id="Logo_x5F_Schatten">
<circle class="st3" cx="24.3" cy="24.3" r="21.7"/>
<polygon class="st4" points="21.4,22.9 15.8,42.4 27.5,25.7 33.2,6.2 "/>
</g>
<g id="LogooVordergrund">
<circle class="st5" cx="23.7" cy="23.7" r="21.7"/>
<g>
<polygon class="st6" points="14.9,41.8 26.6,25.1 20.5,22.2 "/>
<polygon class="st7" points="32.3,5.5 20.5,22.2 26.6,25.1 "/>
<polyline class="st8" points="14.9,41.8 26.6,25.1 32.3,5.5 "/>
<circle class="st9" cx="23.6" cy="23.6" r="1.6"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 873 B

After

Width:  |  Height:  |  Size: 1.6 KiB

@ -3,37 +3,38 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 48 48" style="enable-background:new 0 0 48 48;" xml:space="preserve">
<style type="text/css">
.st0{opacity:0.27;fill:url(#SVGID_1_);}
.st1{fill:none;stroke:#999999;stroke-width:3.3;stroke-miterlimit:10;}
.st2{fill:none;stroke:#508480;stroke-width:3.2;stroke-miterlimit:10;}
.st3{fill:none;stroke:url(#SVGID_00000121983970493329986990000017723393330248815746_);stroke-width:3.2;stroke-miterlimit:10;}
.st4{fill:#999999;}
.st5{fill:#BADDD9;}
.st6{fill:#508480;}
.st7{opacity:0.36;}
.st8{opacity:0.24;fill:#FFFFFF;}
.st0{display:none;}
.st1{display:inline;fill:#254D49;}
.st2{opacity:0.27;fill:url(#SVGID_1_);}
.st3{fill:none;stroke:#1B2E2C;stroke-width:3;stroke-miterlimit:10;}
.st4{fill:#1B2E2C;}
.st5{fill:none;stroke:#508480;stroke-width:3.2;stroke-miterlimit:10;}
.st6{fill:#BADDD9;}
.st7{fill:#508480;}
.st8{opacity:0.36;}
.st9{opacity:0.24;fill:#FFFFFF;}
</style>
<g id="Logo_x5F_Schatten">
<radialGradient id="SVGID_1_" cx="20.8612" cy="20.647" r="22.9444" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#FFFFFF"/>
<g id="Hintergrund_x5F_Uni" class="st0">
<rect class="st1" width="48" height="48"/>
</g>
<g id="Verlauf">
<radialGradient id="SVGID_1_" cx="23.348" cy="21.0566" r="25.4002" fx="3.9002" fy="4.7179" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#000000;stop-opacity:0"/>
<stop offset="1" style="stop-color:#000000"/>
</radialGradient>
<circle class="st0" cx="23.6" cy="23.6" r="22.9"/>
<circle class="st1" cx="24.3" cy="24.3" r="21.7"/>
<circle class="st2" cx="23.6" cy="23.6" r="22.9"/>
</g>
<g id="Logo_x5F_Schatten">
<circle class="st3" cx="24.3" cy="24.3" r="21.7"/>
<polygon class="st4" points="21.4,22.9 15.8,42.4 27.5,25.7 33.2,6.2 "/>
</g>
<g id="LogooVordergrund">
<circle class="st2" cx="23.7" cy="23.7" r="21.7"/>
<linearGradient id="SVGID_00000165954078947660943750000008230134672540192957_" gradientUnits="userSpaceOnUse" x1="3.5175" y1="12.0447" x2="43.8685" y2="35.3413">
<stop offset="0" style="stop-color:#BADDD9;stop-opacity:0.1"/>
<stop offset="1" style="stop-color:#508480"/>
</linearGradient>
<circle style="fill:none;stroke:url(#SVGID_00000165954078947660943750000008230134672540192957_);stroke-width:3.2;stroke-miterlimit:10;" cx="23.7" cy="23.7" r="21.7"/>
<polygon class="st4" points="21.2,23 15.2,43.9 27.7,26 33.7,5 "/>
<polygon class="st5" points="14.3,43.2 26.8,25.2 20.3,22.2 "/>
<polygon class="st6" points="32.8,4.3 20.3,22.2 26.8,25.2 "/>
<polyline class="st7" points="14.3,43.2 26.8,25.2 32.8,4.3 "/>
<circle class="st8" cx="23.6" cy="23.6" r="1.5"/>
<circle class="st5" cx="23.7" cy="23.7" r="21.7"/>
<g>
<polygon class="st6" points="14.9,41.8 26.6,25.1 20.5,22.2 "/>
<polygon class="st7" points="32.3,5.5 20.5,22.2 26.6,25.1 "/>
<polyline class="st8" points="14.9,41.8 26.6,25.1 32.3,5.5 "/>
<circle class="st9" cx="23.6" cy="23.6" r="1.6"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Loading…
Cancel
Save