Skip to content

Fix mc config no longer being available in CI #36

Fix mc config no longer being available in CI

Fix mc config no longer being available in CI #36

Workflow file for this run

name: "CI"
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
determine-changes:
name: Determine Changes
runs-on: ubuntu-latest
outputs:
backend: ${{ steps.changes.outputs.backend }}
frontend: ${{ steps.changes.outputs.frontend }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
id: changes
with:
filters: |
backend:
- 'backend/**' # Added filter for backend directory
frontend:
- 'frontend/**' # Added filter for frontend directory
tests:
name: Run Django Unit Tests
runs-on: ubuntu-latest
container: python:3.8 # version when installing python3 from apt (same as Dockerfile)
needs: determine-changes
if: ${{ needs.determine-changes.outputs.backend == 'true' }}
services:
postgres:
image: postgres:16
env:
POSTGRES_DB: testdb
POSTGRES_USER: testuser
POSTGRES_PASSWORD: testpw
minio:
# We use a third party image for minio which sets the CMD to
# 'server /data', because the official image does not have a default
# CMD and GitHub Actions has not implemented the ability to set the
# launch command for a service.
image: maragudk/minio-ci:latest
env:
MINIO_ACCESS_KEY: minio
MINIO_SECRET_KEY: minio123
MINIO_DOMAIN: minio
steps:
- uses: actions/checkout@v4
- name: Cache pip dependencies
uses: actions/cache@v4
with:
path: backend/.cache/pip
key: ${{ runner.os }}-pip-dependencies-${{ hashFiles('backend/requirements.txt') }}
- name: Install mc
# Install mc so that we can create the community-solutions bucket in minio
run: |
curl https://dl.min.io/client/mc/release/linux-amd64/mc --create-dirs -o mc
chmod +x ./mc
./mc alias set myminio http://minio:9000 minio minio123
./mc mb myminio/community-solutions
- name: Install poppler
# Install poppler to get pdftotext binary
run: |
apt update && apt install -y --no-install-recommends poppler-utils
- name: Install pip dependencies
run: |
pip3 install -r backend/requirements.txt
pip3 install tblib
- name: Make/copy files
# Make/copy files (same as Dockerfile definition) to make resources availabe to tests
run: |
mkdir backend/intermediate_pdf_storage
mv ./frontend/public/exam10.pdf backend
mv ./frontend/public/static backend
- name: Run Django unit tests
env:
SIP_POSTGRES_DB_NAME: testdb
SIP_POSTGRES_DB_USER: testuser
SIP_POSTGRES_DB_PW: testpw
SIP_POSTGRES_DB_SERVER: postgres
SIP_POSTGRES_DB_PORT: 5432
SIP_S3_FILES_HOST: minio
SIP_S3_FILES_PORT: 9000
SIP_S3_FILES_ACCESS_KEY: minio
SIP_S3_FILES_SECRET_KEY: minio123
SIP_S3_FILES_BUCKET: community-solutions
SIP_S3_FILES_USE_SSL: false
run: |
cd backend
python3 manage.py test --parallel # parallel speeds up by approx 4x.
typecheck-lint:
name: Frontend Typecheck & Lint
runs-on: ubuntu-latest
container: node:20
needs: determine-changes
# Only run for pull requests, since on pushes to the default branch, the
# Docker image building step will run the frontend build anyway.
if: ${{ (needs.determine-changes.outputs.frontend == 'true') && (github.event_name == 'pull_request') }}
steps:
- uses: actions/checkout@v4
- name: Cache node modules
uses: actions/cache@v4
with:
path: frontend/.yarn-cache
key: ${{ runner.os }}-node-modules-${{ hashFiles('frontend/yarn.lock') }}
- name: Install node dependencies
run: |
cd frontend
echo 'yarn-offline-mirror ".yarn-cache/"' >> .yarnrc
echo 'yarn-offline-mirror-pruning true' >> .yarnrc
yarn --ignore-engines
- name: Run typecheck
run: |
cd frontend
yarn run tsc
- name: Run lint
run: |
cd frontend
yarn run eslint 'src/**/*.{js,jsx,ts,tsx}'
build-push-image:
name: Build and Push Docker Image
runs-on: ubuntu-latest
# Run this jobas long as the previous jobs have not failed or been cancelled
# (allow skips).
# Don't run on pull requests, only on pushes to the default branch
if: ${{ !failure() && !cancelled() && (github.event_name == 'push') && (github.ref_name == github.event.repository.default_branch) }}
# Requires all tests and build checks to pass
needs: [tests, typecheck-lint]
# Job token must have write permissions to the registry
permissions:
contents: read
packages: write
attestations: write
id-token: write
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
# Set a commit sha-based tag
type=sha,prefix=,suffix=,format=short
# Set a 'latest' tag'
type=raw,value=latest,enable={{is_default_branch}}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
git_branch=${{ github.ref_name }}
git_commit=${{ github.sha }}
cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-buildcache:cache
cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-buildcache:cache,mode=max
deploy:
name: Deploy
runs-on: ubuntu-latest
needs: build-push-image
# This job uses production environment secrets, so it should only run on
# pushes to the default branch (master). This job would probably also run on
# forked repository's default branches, but they wouldn't have access to the
# production secrets that's set in the GitHub repository settings UI.
if: ${{ !failure() && !cancelled() && github.event_name == 'push' && github.ref_name == github.event.repository.default_branch }}
environment: production
steps:
- name: Rolling out to Production Kubernetes
# The service account token should have the permissions for deployment and
# replicaset get and patch.
#
# --fail is crucial
# It sets the exit code to 22 on error, stopping the script.
# --silent is optional for making the output cleaner
# --output is for not printing the API response as it may contain some
# confidential information. To debug any errors, use the command locally.
# --insecure is required
# This is to access the k8s endpoint without a valid client-side
# certificate as otherwise cURL will complain about self-signed
# server-side certs.
# --location
# Makes it follow redirects and isn't necessary but doesn't hurt to have
# --request PATCH and the --data-raw
# The request modifies a harmless annotation on the deployment, which has
# the same overall effect as restarting the deployment:
# `kubectl rollout restart deployment`.
# The restart causes the deployment to pull the latest image from the
# GitLab registry and restart the pods. If the pods don't successfully
# start up (due to a critical failure), the previous deployment stays.
env:
PRODUCTION_K8S_DEPLOYMENT_URL: ${{ secrets.PRODUCTION_K8S_DEPLOYMENT_URL }}
PRODUCTION_K8S_SA_TOKEN: ${{ secrets.PRODUCTION_K8S_SA_TOKEN }}
run: |
set -euo pipefail
curl "${PRODUCTION_K8S_DEPLOYMENT_URL}?fieldManager=kubectl-rollout" \
--fail \
--silent \
--output /dev/null \
--header "Content-Type: application/strategic-merge-patch+json" \
--header "Authorization: Bearer $(echo "$PRODUCTION_K8S_SA_TOKEN" | base64 -d)" \
--insecure \
--location \
--request PATCH \
--data-raw "{
\"spec\": {
\"template\": {
\"metadata\": {
\"annotations\": {
\"kubectl.kubernetes.io/restartedAt\": \"$(date -u +"%Y-%m-%dT%H:%M:%SZ")\"
}
}
}
}
}"
echo "Rollout complete."