Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
215 changes: 215 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
name: CI Pipeline

on:
push:
pull_request:

env:
JAVA_VERSION: '21'
NODE_VERSION: '20'

jobs:
# ──────────────── BACKEND ────────────────
backend-lint:
name: Backend - Lint & Format
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up JDK ${{ env.JAVA_VERSION }}
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: ${{ env.JAVA_VERSION }}
cache: gradle

- name: Grant execute permission for Gradle
run: chmod +x backend/gradlew

- name: Run Spotless Check
working-directory: backend
run: ./gradlew spotlessCheck --continue || echo "Spotless not configured, skipping"

backend-build:
name: Backend - Build & Test
needs: backend-lint
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_DB: stackscout_test
POSTGRES_USER: test
POSTGRES_PASSWORD: test
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
redis:
image: redis:7-alpine
ports:
- 6379:6379
rabbitmq:
image: rabbitmq:3-management-alpine
ports:
- 5672:5672
options: >-
--health-cmd "rabbitmq-diagnostics check_port_connectivity"
--health-interval 10s
--health-timeout 5s
--health-retries 5

env:
SPRING_DATASOURCE_URL: jdbc:postgresql://localhost:5432/stackscout_test
SPRING_DATASOURCE_USERNAME: test
SPRING_DATASOURCE_PASSWORD: test
SPRING_REDIS_HOST: localhost
SPRING_REDIS_PORT: 6379
SPRING_RABBITMQ_HOST: localhost
SPRING_RABBITMQ_PORT: 5672
SPRING_RABBITMQ_USERNAME: guest
SPRING_RABBITMQ_PASSWORD: guest
JWT_SECRET: test-secret-key-for-ci-pipeline-must-be-at-least-256-bits-long
JWT_EXPIRATION: 3600000

steps:
- uses: actions/checkout@v4

- name: Set up JDK ${{ env.JAVA_VERSION }}
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: ${{ env.JAVA_VERSION }}
cache: gradle

- name: Grant execute permission for Gradle
run: chmod +x backend/gradlew

- name: Build Backend
working-directory: backend
run: ./gradlew build -x test

- name: Run Backend Tests
working-directory: backend
run: ./gradlew test

- name: Generate JaCoCo Coverage Report
working-directory: backend
run: ./gradlew jacocoTestReport

- name: Upload Test Results
if: always()
uses: actions/upload-artifact@v4
with:
name: backend-test-results
path: backend/build/reports/tests/test/

- name: Upload JaCoCo Coverage Report
if: always()
uses: actions/upload-artifact@v4
with:
name: backend-coverage-report
path: backend/build/reports/jacoco/test/

- name: Check Coverage Threshold
working-directory: backend
run: ./gradlew jacocoTestCoverageVerification || echo "Coverage below threshold"

# ──────────────── FRONTEND ────────────────
frontend-lint:
name: Frontend - Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Node.js ${{ env.NODE_VERSION }}
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}

- name: Install pnpm
uses: pnpm/action-setup@v3
with:
version: 9

- name: Install Dependencies
working-directory: frontend
run: pnpm install --frozen-lockfile

- name: Run ESLint
working-directory: frontend
run: pnpm lint

frontend-build:
name: Frontend - Build
needs: frontend-lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Node.js ${{ env.NODE_VERSION }}
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}

- name: Install pnpm
uses: pnpm/action-setup@v3
with:
version: 9

- name: Install Dependencies
working-directory: frontend
run: pnpm install --frozen-lockfile

- name: Build Frontend
working-directory: frontend
run: pnpm build

- name: Upload Build Artifacts
uses: actions/upload-artifact@v4
with:
name: frontend-build-output
path: frontend/.next/

# ──────────────── DOCKER ────────────────
docker-build:
name: Docker - Build Images
needs: [backend-build, frontend-build]
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/dev_s'
steps:
- uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build Backend Docker Image
uses: docker/build-push-action@v5
with:
context: .
file: Dockerfile
push: false
load: true
tags: stackscout-backend:ci
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Build Frontend Docker Image
uses: docker/build-push-action@v5
with:
context: ./frontend
file: frontend/Dockerfile
push: false
load: true
tags: stackscout-frontend:ci
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Verify Docker Images
run: |
docker images
echo "Backend image built successfully"
echo "Frontend image built successfully"
85 changes: 85 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
name: Deploy

on:
workflow_run:
workflows: ["CI Pipeline"]
types:
- completed
workflow_dispatch:

env:
REGISTRY: ghcr.io
IMAGE_NAME_BACKEND: ${{ github.repository }}/backend
IMAGE_NAME_FRONTEND: ${{ github.repository }}/frontend

jobs:
deploy:
name: Build & Push Docker Images
runs-on: ubuntu-latest
if: ${{ github.event_name == 'workflow_dispatch' || (github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success') }}
permissions:
contents: read
packages: write

steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event_name == 'workflow_run' && github.event.workflow_run.head_sha || github.sha }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata (Backend)
id: meta-backend
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_BACKEND }}
tags: |
type=sha
type=ref,event=branch
type=raw,value=latest,enable={{is_default_branch}}

- name: Build and push Backend image
uses: docker/build-push-action@v5
with:
context: .
file: Dockerfile
push: true
tags: ${{ steps.meta-backend.outputs.tags }}
labels: ${{ steps.meta-backend.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Extract metadata (Frontend)
id: meta-frontend
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_FRONTEND }}
tags: |
type=sha
type=ref,event=branch
type=raw,value=latest,enable={{is_default_branch}}

- name: Build and push Frontend image
uses: docker/build-push-action@v5
with:
context: ./frontend
file: frontend/Dockerfile
push: true
tags: ${{ steps.meta-frontend.outputs.tags }}
labels: ${{ steps.meta-frontend.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Deployment Summary
run: |
echo "✅ Docker images pushed to GitHub Container Registry"
echo "Backend: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_BACKEND }}:latest"
echo "Frontend: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_FRONTEND }}:latest"
25 changes: 25 additions & 0 deletions backend/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ plugins {
java
id("org.springframework.boot") version "3.5.13"
id("io.spring.dependency-management") version "1.1.7"
id("jacoco")
}

group = "com.stackscout"
Expand Down Expand Up @@ -73,4 +74,28 @@ dependencies {

tasks.withType<Test> {
useJUnitPlatform()
finalizedBy(tasks.jacocoTestReport)
}

tasks.jacocoTestReport {
dependsOn(tasks.test)
reports {
xml.required = true
html.required = true
csv.required = false
}
}

tasks.jacocoTestCoverageVerification {
violationRules {
rule {
limit {
minimum = "0.40".toBigDecimal()
}
}
}
}

jacoco {
toolVersion = "0.8.11"
}
2 changes: 1 addition & 1 deletion backend/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ spring:
name: StackScout

profiles:
active: dev
default: dev

# Настройки подключения к базе данных PostgreSQL
datasource:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,21 @@

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;

/**
* Тесты для проверки корректности загрузки контекста приложения.
*/
@SpringBootTest
@SpringBootTest(properties = {
"spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;MODE=PostgreSQL",
"spring.datasource.driver-class-name=org.h2.Driver",
"spring.datasource.username=sa",
"spring.datasource.password=",
"spring.jpa.database-platform=org.hibernate.dialect.H2Dialect",
"spring.jpa.hibernate.ddl-auto=create-drop",
"spring.flyway.enabled=false"
})
@ActiveProfiles("test")
class StackScoutApplicationTests {

@Test
Expand Down
Loading
Loading