diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml new file mode 100644 index 0000000..a3c6cfb --- /dev/null +++ b/.github/workflows/build-docker.yml @@ -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 }}" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index 7605281..0000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -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 diff --git a/README.md b/README.md index 9fc1c8c..e5c47f0 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/docker/test/Dockerfile b/docker/test/Dockerfile index 3005167..47f31d4 100644 --- a/docker/test/Dockerfile +++ b/docker/test/Dockerfile @@ -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