From 548a43de01f5db019240b40380726ff36914f858 Mon Sep 17 00:00:00 2001 From: AnhAnNek Date: Sat, 9 May 2026 14:29:38 +0700 Subject: [PATCH] config --- .dockerignore | 16 ++++++ .gitea/workflows/test.yml | 21 -------- Jenkinsfile | 111 ++++++++++++++++++++++++++++++++++++++ backend/Dockerfile | 19 ++++--- docker-compose.yml | 52 ++++++++++++++++++ frontend/Dockerfile | 22 +++++--- sonar-project.properties | 15 +++--- 7 files changed, 214 insertions(+), 42 deletions(-) create mode 100644 .dockerignore delete mode 100644 .gitea/workflows/test.yml create mode 100644 Jenkinsfile create mode 100644 docker-compose.yml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..59f7a47 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,16 @@ +**/.git +**/.gitignore +**/.github +**/.idea +**/.vscode +**/node_modules +**/target +**/.next +**/storybook-static +**/dist +**/build +**/coverage +**/*.log +Dockerfile* +docker-compose*.yml +README.md diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml deleted file mode 100644 index a4ffc8b..0000000 --- a/.gitea/workflows/test.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: Test Runner - -on: - push: - branches: - - main - - master - - develop - -jobs: - test: - runs-on: ubuntu-latest - steps: - - name: Hello - run: echo "Runner is working" - - - - - - \ No newline at end of file diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..058712b --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,111 @@ +pipeline { + agent any + environment { + MAVEN_CACHE = "${env.WORKSPACE}/.m2" + NPM_CACHE = "${env.WORKSPACE}/.npm-cache" + SONAR_TOKEN = credentials('sonar-token') + } + options { + ansiColor('xterm') + timestamps() + skipStagesAfterUnstable() + } + stages { + stage('Checkout') { + steps { + checkout scm + } + } + stage('Backend: Build & Test') { + agent { + docker { + image 'maven:3.9.9-eclipse-temurin-21' + args "-v ${env.WORKSPACE}/.m2:/root/.m2" + } + } + environment { + MAVEN_OPTS = '-Dmaven.repo.local=/root/.m2/repository' + } + steps { + dir('backend') { + sh './mvnw --version' + sh './mvnw clean test -Dmaven.repo.local=/root/.m2/repository' + sh './mvnw package -DskipTests -Dmaven.repo.local=/root/.m2/repository' + } + } + post { + always { + junit 'backend/target/surefire-reports/*.xml' + } + } + } + stage('Backend: SonarQube Analysis') { + agent { + docker { + image 'maven:3.9.9-eclipse-temurin-21' + args "-v ${env.WORKSPACE}/.m2:/root/.m2" + } + } + steps { + withSonarQubeEnv('SonarQube') { + dir('backend') { + sh './mvnw sonar:sonar -Dsonar.projectKey=code-journey-backend -Dsonar.host.url=${SONAR_HOST_URL} -Dsonar.login=${SONAR_TOKEN} -Dmaven.repo.local=/root/.m2/repository' + } + } + } + } + stage('Frontend: Install & Build') { + agent { + docker { + image 'node:20-alpine' + args "-v ${env.WORKSPACE}/.npm-cache:/root/.npm -u root" + } + } + steps { + dir('frontend') { + sh 'npm ci --cache /root/.npm --prefer-offline' + sh 'npm run build' + } + } + } + stage('Frontend: SonarQube Analysis') { + agent { + docker { + image 'node:20-alpine' + args "-v ${env.WORKSPACE}/.npm-cache:/root/.npm -u root" + } + } + steps { + withSonarQubeEnv('SonarQube') { + dir('frontend') { + sh 'npm install -g sonar-scanner' + sh 'sonar-scanner -Dsonar.projectKey=code-journey-frontend -Dsonar.sources=src -Dsonar.host.url=${SONAR_HOST_URL} -Dsonar.login=${SONAR_TOKEN}' + } + } + } + } + stage('Docker: Build Images') { + when { + anyOf { + branch 'main' + branch 'develop' + } + } + agent { + docker { + image 'docker:24.0.5-dind' + args '--privileged -v /var/run/docker.sock:/var/run/docker.sock' + } + } + steps { + sh 'docker build -t code-journey-backend:latest backend' + sh 'docker build -t code-journey-frontend:latest frontend' + } + } + } + post { + always { + archiveArtifacts artifacts: 'backend/target/*.jar,frontend/.next/**', allowEmptyArchive: true + } + } +} diff --git a/backend/Dockerfile b/backend/Dockerfile index 1887237..5a5b03b 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,12 +1,17 @@ -# Build stage +# Build stage FROM maven:3.9.9-eclipse-temurin-21 AS build WORKDIR /app -COPY . . -RUN mvn clean package -DskipTests +COPY .mvn .mvn +COPY mvnw . +COPY pom.xml . +RUN chmod +x mvnw +RUN ./mvnw -B -q dependency:go-offline +COPY src ./src +RUN ./mvnw -B clean package -DskipTests # Runtime stage -FROM eclipse-temurin:21-jdk +FROM eclipse-temurin:21-jdk AS runtime WORKDIR /app -COPY --from=build /app/target/*.jar app.jar -EXPOSE 8080 -ENTRYPOINT ["java", "-jar", "app.jar"] \ No newline at end of file +COPY --from=build /app/target/*.jar ./app.jar +EXPOSE 8888 +ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar /app/app.jar"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..5b6fe6d --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,52 @@ +version: '3.9' + +services: + postgres: + image: postgres:17.2 + restart: unless-stopped + environment: + POSTGRES_DB: ${DB_NAME:-code_journey} + POSTGRES_USER: ${DB_USER:-postgres} + POSTGRES_PASSWORD: ${DB_PASS:-postgres} + volumes: + - postgres_data:/var/lib/postgresql/data + networks: + - app_net + + backend: + build: + context: ./backend + dockerfile: Dockerfile + restart: unless-stopped + depends_on: + - postgres + environment: + DB_URL: jdbc:postgresql://${DB_HOST:-postgres}:${DB_PORT:-5432}/${DB_NAME:-code_journey} + DB_USER: ${DB_USER:-postgres} + DB_PASS: ${DB_PASS:-postgres} + ports: + - "8080:8888" + networks: + - app_net + + frontend: + build: + context: ./frontend + dockerfile: Dockerfile + restart: unless-stopped + depends_on: + - backend + environment: + NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://backend:8888} + NODE_ENV: production + ports: + - "3000:3000" + networks: + - app_net + +volumes: + postgres_data: + +networks: + app_net: + driver: bridge diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 8407641..f1f4777 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -1,14 +1,24 @@ +# Dependencies stage +FROM node:20-alpine AS deps +WORKDIR /app +COPY package.json package-lock.json ./ +RUN npm ci + # Build stage FROM node:20-alpine AS builder WORKDIR /app -COPY package*.json ./ -RUN npm install COPY . . +COPY --from=deps /app/node_modules ./node_modules RUN npm run build -# Production stage -FROM node:20-alpine +# Runtime stage +FROM node:20-alpine AS runner WORKDIR /app -COPY --from=builder /app ./ +ENV NODE_ENV=production +COPY --from=builder /app/package.json ./package.json +COPY --from=builder /app/package-lock.json ./package-lock.json +COPY --from=builder /app/.next ./.next +COPY --from=builder /app/public ./public +COPY --from=builder /app/node_modules ./node_modules EXPOSE 3000 -CMD ["npm", "start"] \ No newline at end of file +CMD ["npm", "start"] diff --git a/sonar-project.properties b/sonar-project.properties index 52958d6..0a7b577 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,11 +1,10 @@ -sonar.projectKey=code-journey +sonar.projectKey=code-journey sonar.projectName=code-journey -sonar.sources=backend/src/main,frontend/src - +sonar.projectVersion=1.0.0 +sonar.sources=backend/src/main/java,frontend/src +sonar.tests=backend/src/test/java sonar.sourceEncoding=UTF-8 - -# Java configuration sonar.java.binaries=backend/target/classes - -# Exclusions for build outputs and dependencies -sonar.exclusions=**/node_modules/**,**/vendor/**,**/dist/**,**/build/**,**/storage/**,**/tmp/**,**/target/**,**/storybook-static/**,.next/** \ No newline at end of file +sonar.exclusions=**/node_modules/**,**/target/**,**/.next/**,**/storybook-static/**,**/build/**,**/*.log +sonar.coverage.exclusions=**/*Test.java,**/*Spec.java +sonar.test.inclusions=backend/src/test/java/**