Skip to content

Bump picomatch in /frontend #148

Bump picomatch in /frontend

Bump picomatch in /frontend #148

Workflow file for this run

name: Deploy
on:
push:
branches:
- master
pull_request:
branches:
- master
release:
types: [published]
issue_comment:
types: [created]
workflow_dispatch:
inputs:
environment:
description: "Environment to deploy"
required: true
type: choice
options:
- test
- master
- release
permissions:
contents: read
pull-requests: write
issues: write
env:
REGISTRY: ghcr.io
IMAGE_NAME_BASE: universalscientifictechnologies/dosportal
jobs:
backend-tests:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Build backend image
run: docker compose -p "ci-${{ github.run_id }}" -f docker-compose.yml build backend
- name: Create .env file for tests
run: cp .env.example .env
- name: Start dependencies
run: docker compose -p "ci-${{ github.run_id }}" -f docker-compose.yml up -d db_dosportal redis minio
- name: Run backend tests
run: docker compose -p "ci-${{ github.run_id }}" -f docker-compose.yml run --rm --entrypoint "pytest" backend DOSPORTAL/tests/
- name: Shutdown services
if: always()
run: docker compose -p "ci-${{ github.run_id }}" -f docker-compose.yml down -v
build-check:
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
strategy:
matrix:
include:
- component: backend
dockerfile: backend.Dockerfile
- component: frontend
dockerfile: frontend.Dockerfile
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build Docker image (${{ matrix.component }})
uses: docker/build-push-action@v6
with:
context: .
file: ${{ matrix.dockerfile }}
push: false
build-args: |
GIT_COMMIT=${{ github.sha }}
GIT_BRANCH=${{ github.head_ref }}
# Determine deployment environment
prepare:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
issues: write
deployments: write
outputs:
should_deploy: ${{ steps.check.outputs.should_deploy }}
environment: ${{ steps.check.outputs.environment }}
image_tag: ${{ steps.check.outputs.image_tag }}
app_dir: ${{ steps.check.outputs.app_dir }}
project_name: ${{ steps.check.outputs.project_name }}
comment_id: ${{ steps.react.outputs.comment_id }}
deployment_id: ${{ steps.create_deployment.outputs.deployment_id }}
steps:
- name: React to PR comment
if: github.event_name == 'issue_comment'
id: react
uses: actions/github-script@v7
with:
script: |
await github.rest.reactions.createForIssueComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: context.payload.comment.id,
content: 'eyes'
});
core.setOutput('comment_id', context.payload.comment.id);
- name: Check deployment conditions
id: check
env:
COMMENT_BODY: ${{ github.event.comment.body }}
run: |
SHOULD_DEPLOY="false"
ENVIRONMENT=""
IMAGE_TAG=""
APP_DIR=""
PROJECT_NAME=""
# Release (tag or published release)
if [[ "${{ github.event_name }}" == "release" || ( "${{ github.event_name }}" == "push" && "${{ github.ref }}" == refs/tags/v* ) ]]; then
SHOULD_DEPLOY="true"
ENVIRONMENT="release"
if [[ "${{ github.event_name }}" == "release" ]]; then
IMAGE_TAG="${{ github.event.release.tag_name }}"
else
IMAGE_TAG="${GITHUB_REF#refs/tags/}"
fi
APP_DIR="/data/ust/dosportal/release"
PROJECT_NAME="dosportal-release"
# Master branch (master or dev)
elif [[ "${{ github.event_name }}" == "push" && ( "${{ github.ref }}" == "refs/heads/master" || "${{ github.ref }}" == "refs/heads/dev" ) ]]; then
SHOULD_DEPLOY="true"
ENVIRONMENT="master"
IMAGE_TAG="master"
APP_DIR="/data/ust/dosportal/master"
PROJECT_NAME="dosportal-master"
# PR comment with /test-me
elif [[ "${{ github.event_name }}" == "issue_comment" ]]; then
if [[ "$COMMENT_BODY" == *"/test-me"* ]] && [[ "${{ github.event.issue.pull_request }}" != "" ]]; then
SHOULD_DEPLOY="true"
ENVIRONMENT="test"
IMAGE_TAG="pr-${{ github.event.issue.number }}"
APP_DIR="/data/ust/dosportal/test"
PROJECT_NAME="dosportal-test"
fi
# Manual workflow dispatch
elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
SHOULD_DEPLOY="true"
ENVIRONMENT="${{ inputs.environment }}"
if [[ "$ENVIRONMENT" == "release" ]]; then
IMAGE_TAG="latest"
APP_DIR="/data/ust/dosportal/release"
PROJECT_NAME="dosportal-release"
elif [[ "$ENVIRONMENT" == "master" ]]; then
IMAGE_TAG="master"
APP_DIR="/data/ust/dosportal/master"
PROJECT_NAME="dosportal-master"
elif [[ "$ENVIRONMENT" == "test" ]]; then
IMAGE_TAG="test"
APP_DIR="/data/ust/dosportal/test"
PROJECT_NAME="dosportal-test"
fi
fi
echo "should_deploy=$SHOULD_DEPLOY" >> $GITHUB_OUTPUT
echo "environment=$ENVIRONMENT" >> $GITHUB_OUTPUT
echo "image_tag=$IMAGE_TAG" >> $GITHUB_OUTPUT
echo "app_dir=$APP_DIR" >> $GITHUB_OUTPUT
echo "project_name=$PROJECT_NAME" >> $GITHUB_OUTPUT
echo "Deployment decision:"
echo " Should deploy: $SHOULD_DEPLOY"
echo " Environment: $ENVIRONMENT"
echo " Image tag: $IMAGE_TAG"
- name: Create GitHub deployment
if: steps.check.outputs.should_deploy == 'true' && steps.check.outputs.environment == 'test' && github.event_name == 'issue_comment'
id: create_deployment
uses: actions/github-script@v7
with:
script: |
const deployment = await github.rest.repos.createDeployment({
owner: context.repo.owner,
repo: context.repo.repo,
ref: 'refs/pull/${{ github.event.issue.number }}/head',
environment: 'test',
description: 'Test deployment for PR #${{ github.event.issue.number }}',
auto_merge: false,
required_contexts: []
});
core.setOutput('deployment_id', deployment.data.id);
await github.rest.repos.createDeploymentStatus({
owner: context.repo.owner,
repo: context.repo.repo,
deployment_id: deployment.data.id,
state: 'in_progress',
description: 'Deployment in progress'
});
build-and-push:
runs-on: ubuntu-latest
needs: [prepare]
if: needs.prepare.outputs.should_deploy == 'true'
permissions:
contents: read
packages: write
strategy:
matrix:
include:
- component: backend
dockerfile: backend.Dockerfile
- component: frontend
dockerfile: frontend.Dockerfile
steps:
- name: Get PR info if needed
if: github.event_name == 'issue_comment'
id: pr_info
uses: actions/github-script@v7
with:
script: |
const pr = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number
});
core.setOutput('ref', pr.data.head.ref);
core.setOutput('sha', pr.data.head.sha);
core.setOutput('repo', pr.data.head.repo.full_name);
- name: Checkout repository
uses: actions/checkout@v6
with:
repository: ${{ github.event_name == 'issue_comment' && steps.pr_info.outputs.repo || github.repository }}
ref: ${{ github.event_name == 'issue_comment' && steps.pr_info.outputs.ref || github.ref }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- 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_BASE }}-${{ matrix.component }}
tags: |
type=ref,event=branch
type=ref,event=tag
type=semver,pattern={{version}}
type=raw,value=${{ needs.prepare.outputs.image_tag }}
- name: Build and push Docker image (${{ matrix.component }})
uses: docker/build-push-action@v6
with:
context: .
file: ${{ matrix.dockerfile }}
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GIT_COMMIT=${{ github.event_name == 'issue_comment' && steps.pr_info.outputs.sha || github.sha }}
GIT_BRANCH=${{ github.event_name == 'issue_comment' && steps.pr_info.outputs.ref || github.ref_name }}
cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME_BASE }}-${{ matrix.component }}:buildcache
cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME_BASE }}-${{ matrix.component }}:buildcache,mode=max
deploy:
name: Deploy to ${{ needs.prepare.outputs.environment }}
needs: [prepare, build-and-push, backend-tests]
if: >
always() &&
needs.prepare.outputs.should_deploy == 'true' &&
needs.build-and-push.result == 'success' &&
(
needs.prepare.outputs.environment == 'test' ||
needs.backend-tests.result == 'success'
)
runs-on: ubuntu-latest
permissions:
contents: read
deployments: write
environment:
name: ${{ needs.prepare.outputs.environment }}
url: ${{ needs.prepare.outputs.environment == 'release' && 'https://portal.dos.ust.cz' || (needs.prepare.outputs.environment == 'master' && 'https://master.portal.dos.ust.cz' || '') }}
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Read docker-compose file
id: compose_file
run: |
COMPOSE_CONTENT=$(cat docker-compose.prod.yml | base64 -w 0)
echo "content=$COMPOSE_CONTENT" >> $GITHUB_OUTPUT
- name: Deploy via SSH
uses: appleboy/ssh-action@v1.0.3
env:
APP_DIR: ${{ needs.prepare.outputs.app_dir }}
ENV_FILE: ${{ needs.prepare.outputs.app_dir }}/env/${{ needs.prepare.outputs.environment }}.env
COMPOSE_FILE: docker-compose.prod.yml
PROJECT_NAME: ${{ needs.prepare.outputs.project_name }}
REGISTRY: ${{ env.REGISTRY }}
IMAGE_NAME_BASE: ${{ env.IMAGE_NAME_BASE }}
IMAGE_TAG: ${{ needs.prepare.outputs.image_tag }}
COMPOSE_CONTENT: ${{ steps.compose_file.outputs.content }}
with:
host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.DEPLOY_SSH_KEY }}
envs: APP_DIR,ENV_FILE,COMPOSE_FILE,PROJECT_NAME,REGISTRY,IMAGE_NAME_BASE,IMAGE_TAG,COMPOSE_CONTENT
script: |
set -euo pipefail
echo "==> Deploying to environment: $PROJECT_NAME"
echo "==> Using image tag: $IMAGE_TAG"
echo "==> Preparing app dir"
mkdir -p "$APP_DIR/env"
cd "$APP_DIR"
echo "==> Creating docker-compose file"
echo "$COMPOSE_CONTENT" | base64 -d > "$COMPOSE_FILE"
echo "==> Sanity checks"
test -f "$COMPOSE_FILE" || (echo "Missing compose file: $APP_DIR/$COMPOSE_FILE" && exit 1)
if [ ! -f "$ENV_FILE" ]; then
echo "Creating dummy env file at $ENV_FILE"
touch "$ENV_FILE"
fi
docker version >/dev/null
docker compose version >/dev/null
echo "==> Remove old images with same tag to force fresh pull"
docker rmi "$REGISTRY/$IMAGE_NAME_BASE-backend:$IMAGE_TAG" 2>/dev/null || true
docker rmi "$REGISTRY/$IMAGE_NAME_BASE-frontend:$IMAGE_TAG" 2>/dev/null || true
echo "==> Pull images (explicit, public GHCR)"
docker pull "$REGISTRY/$IMAGE_NAME_BASE-backend:$IMAGE_TAG"
docker pull "$REGISTRY/$IMAGE_NAME_BASE-frontend:$IMAGE_TAG"
echo "==> Check for override file"
COMPOSE_ARGS="-f $COMPOSE_FILE"
if [ -f "docker-compose.override.yml" ]; then
echo "Found docker-compose.override.yml, applying it"
COMPOSE_ARGS="$COMPOSE_ARGS -f docker-compose.override.yml"
fi
echo "==> Compose pull"
docker compose -p "$PROJECT_NAME" $COMPOSE_ARGS --env-file "$ENV_FILE" pull
echo "==> Up (force recreate to apply env changes)"
docker compose -p "$PROJECT_NAME" $COMPOSE_ARGS --env-file "$ENV_FILE" up -d --force-recreate --remove-orphans
echo "==> Initialize DOSPORTAL (migrations + fixtures + MinIO)"
docker exec "${PROJECT_NAME}-backend-1" python manage.py init_dosportal
echo "==> Show status"
docker compose -p "$PROJECT_NAME" $COMPOSE_ARGS ps
echo "==> Cleanup old images (keep recent ones)"
docker image prune -af --filter "until=168h"
echo "==> Done"
- name: Mark deployment as successful
if: needs.prepare.outputs.environment == 'test' && github.event_name == 'issue_comment' && needs.prepare.outputs.deployment_id
uses: actions/github-script@v7
with:
script: |
await github.rest.repos.createDeploymentStatus({
owner: context.repo.owner,
repo: context.repo.repo,
deployment_id: ${{ needs.prepare.outputs.deployment_id }},
state: 'success',
environment_url: 'https://test.portal.dos.ust.cz',
description: 'Deployment completed successfully'
});
- name: Update PR comment with deployment info
if: needs.prepare.outputs.environment == 'test' && github.event_name == 'issue_comment' && needs.prepare.outputs.comment_id
continue-on-error: true
uses: actions/github-script@v7
with:
script: |
const testsResult = '${{ needs.backend-tests.result }}';
const extra = testsResult !== 'success'
? '\n⚠️ Backend tests failed, but test deployment was still performed.'
: '';
try {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: `✅ **Test deployment completed!**\n🔗 Available at: https://test.portal.dos.ust.cz${extra}`
});
} catch (error) {
console.error('Could not create comment:', error.message);
}