name: CI on: push: jobs: backend-test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - name: Set up JDK 25 uses: actions/setup-java@v5 with: distribution: temurin java-version: 25 - name: Run backend verify run: cd backend && ./mvnw -B verify frontend-test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - name: Set up Node 24 uses: actions/setup-node@v6 with: node-version: 24 - name: Install dependencies run: cd frontend && npm ci - name: Lint run: cd frontend && npm run lint - name: Generate API types run: cd frontend && npm run generate:api - name: Type check run: cd frontend && npm run type-check - name: Unit tests run: cd frontend && npm run test:unit -- --run - name: Production build run: cd frontend && npm run build frontend-e2e: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - name: Set up Node 24 uses: actions/setup-node@v6 with: node-version: 24 - name: Install dependencies run: cd frontend && npm ci - name: Install Playwright browsers run: cd frontend && npx playwright install --with-deps chromium - name: Run E2E tests run: cd frontend && npm run test:e2e - name: Upload Playwright report uses: actions/upload-artifact@v7 if: ${{ !cancelled() }} with: name: playwright-report path: frontend/playwright-report/ retention-days: 30 build-and-publish: needs: [backend-test, frontend-test, frontend-e2e] if: startsWith(github.ref, 'refs/tags/') && contains(github.ref_name, '.') runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 with: fetch-depth: 0 - name: Parse SemVer tag id: semver run: | TAG="${{ github.ref_name }}" if [[ ! "$TAG" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then echo "Not a valid SemVer tag: $TAG" exit 1 fi MAJOR="${TAG%%.*}" MINOR="${TAG%.*}" echo "full=$TAG" >> "$GITHUB_OUTPUT" echo "minor=$MINOR" >> "$GITHUB_OUTPUT" echo "major=$MAJOR" >> "$GITHUB_OUTPUT" - name: Build image run: | REGISTRY="${{ github.server_url }}" REGISTRY="${REGISTRY#https://}" REGISTRY="${REGISTRY#http://}" REPO="${{ github.repository }}" IMAGE="${REGISTRY}/${REPO}" docker build -t "${IMAGE}:${{ steps.semver.outputs.full }}" . docker tag "${IMAGE}:${{ steps.semver.outputs.full }}" "${IMAGE}:${{ steps.semver.outputs.minor }}" docker tag "${IMAGE}:${{ steps.semver.outputs.full }}" "${IMAGE}:${{ steps.semver.outputs.major }}" docker tag "${IMAGE}:${{ steps.semver.outputs.full }}" "${IMAGE}:latest" echo "IMAGE=${IMAGE}" >> "$GITHUB_ENV" - name: Push to registry run: | echo "${{ secrets.REGISTRY_TOKEN }}" | docker login -u "${{ github.repository_owner }}" --password-stdin "${IMAGE%%/*}" docker push "${IMAGE}:${{ steps.semver.outputs.full }}" docker push "${IMAGE}:${{ steps.semver.outputs.minor }}" docker push "${IMAGE}:${{ steps.semver.outputs.major }}" docker push "${IMAGE}:latest" - name: Generate changelog id: changelog run: | PREV_TAG=$(git tag --sort=-v:refname | sed -n '2p') if [ -z "$PREV_TAG" ]; then git log --oneline --no-merges > RELEASE_NOTES.md else git log --oneline --no-merges "${PREV_TAG}..HEAD" > RELEASE_NOTES.md fi echo "Container image: \`${IMAGE}:${{ steps.semver.outputs.full }}\`" >> RELEASE_NOTES.md - name: Create Gitea release uses: akkuman/gitea-release-action@v1 with: tag_name: ${{ github.ref_name }} name: v${{ steps.semver.outputs.full }} body_path: RELEASE_NOTES.md token: ${{ github.token }}