diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..d1810b3 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,2 @@ +# Repo owner +* @NikitaBuffy \ No newline at end of file diff --git a/.github/workflows/backend.yml b/.github/workflows/backend.yml new file mode 100644 index 0000000..422dc40 --- /dev/null +++ b/.github/workflows/backend.yml @@ -0,0 +1,56 @@ +name: Java CI + +on: + pull_request: + branches: + - backend + workflow_dispatch: + +jobs: + build-and-test: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up JDK + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + + - name: Cache Maven dependencies + uses: actions/cache@v4 + with: + path: ~/.m2 + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- + + - name: Build project + run: | + cd backend + mvn clean verify + + - name: Upload backend build artifact + uses: actions/upload-artifact@v4 + with: + name: backend-jar + path: /backend/target/*.jar + + - name: Cache SonarQube packages + uses: actions/cache@v4 + with: + path: ~/.sonar/cache + key: ${{ runner.os }}-sonar + restore-keys: ${{ runner.os }}-sonar + + - name: Analyze with SonarQube + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} + SONAR_PROJECT_KEY: ${{ secrets.SONAR_PROJECT_KEY }} + run: | + cd backend + mvn org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=$SONAR_PROJECT_KEY -Dsonar.projectName='lenka-messenger' -Dsonar.pullrequest.key=${{ github.event.number}} -Dsonar.pullrequest.branch=${{ github.event.pull_request.head.ref }} -Dsonar.pullrequest.base=${{ github.event.pull_request.base.ref }} -Dsonar.scm.revision=${{ github.event.pull_request.head.sha }} \ No newline at end of file diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml new file mode 100644 index 0000000..42f301b --- /dev/null +++ b/.github/workflows/frontend.yml @@ -0,0 +1,66 @@ +name: Vue CI + +on: + pull_request: + branches: + - frontend + workflow_dispatch: + +jobs: + build-and-analyze: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '18' + + - name: Cache Node.js dependencies + uses: actions/cache@v4 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node- + + - name: Install dependencies + run: | + cd frontend + npm install + + - name: Build frontend + run: | + cd frontend + npm run build + + - name: Upload frontend build artifact + uses: actions/upload-artifact@v4 + with: + name: frontend-dist + path: frontend/dist/ + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + + - name: Cache SonarQube packages + uses: actions/cache@v4 + with: + path: ~/.sonar/cache + key: ${{ runner.os }}-sonar + restore-keys: ${{ runner.os }}-sonar + + - name: Analyze with SonarQube + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} + SONAR_PROJECT_KEY: ${{ secrets.SONAR_PROJECT_KEY }} + run: | + cd frontend + npx sonar-scanner -Dsonar.projectKey=$SONAR_PROJECT_KEY -Dsonar.projectName='lenka-messenger' -Dsonar.sources=src -Dsonar.pullrequest.key=${{ github.event.number}} -Dsonar.pullrequest.branch=${{ github.event.pull_request.head.ref }} -Dsonar.pullrequest.base=${{ github.event.pull_request.base.ref }} -Dsonar.scm.revision=${{ github.event.pull_request.head.sha }} -Dsonar.host.url=$SONAR_HOST_URL \ No newline at end of file diff --git a/.github/workflows/main-restrict.yml b/.github/workflows/main-restrict.yml new file mode 100644 index 0000000..0e5a9cd --- /dev/null +++ b/.github/workflows/main-restrict.yml @@ -0,0 +1,23 @@ +name: Restrict PR to Main + +on: + pull_request: + branches: + - main + +jobs: + restrict-branches: + runs-on: ubuntu-latest + steps: + - name: Check source branch + run: | + echo "Checking source branch..." + ALLOWED_BRANCHES=("backend" "frontend" "devops") + SOURCE_BRANCH=$(echo "${{ github.event.pull_request.head.ref }}") + + if [[ ! " ${ALLOWED_BRANCHES[@]} " =~ " ${SOURCE_BRANCH} " ]]; then + echo "Pull Request from branch '${SOURCE_BRANCH}' to 'main' is not allowed!" + exit 1 + else + echo "Pull Request from '${SOURCE_BRANCH}' is allowed." + fi \ No newline at end of file diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..32e367a --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,89 @@ +name: Main CD + +on: + pull_request: + types: [closed] + branches: + - main + workflow_dispatch: + +jobs: + cd-backend: + if: github.event.pull_request.merged == true && github.event.pull_request.head.ref == 'backend' + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Log in to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Download Backend Artifact + uses: actions/download-artifact@v4 + with: + name: backend-jar + path: backend/target/ + + - name: Build and Push Backend Image + run: | + cd backend + docker build -t nickpominov/lm-backend:latest . + docker push nickpominov/lm-backend:latest + + - name: Deploy Backend to Remote Server + uses: appleboy/ssh-action@v0.1.7 + with: + host: ${{ secrets.SERVER_IP }} + username: ${{ secrets.SSH_USERNAME }} + password: ${{ secrets.SSH_PASSWORD }} + port: 22 + script: | + cd /srv/lenka-messenger + docker-compose -f docker-compose.prod.yaml up -d --no-deps lm-backend + + cd-frontend: + if: github.event.pull_request.merged == true && github.event.pull_request.head.ref == 'frontend' + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Log in to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Download Frontend Artifact + uses: actions/download-artifact@v4 + with: + name: frontend-dist + path: frontend/dist/ + + - name: Build and Push Frontend Image + run: | + cd frontend + docker build -t nickpominov/lm-frontend:latest . + docker push nickpominov/lm-frontend:latest + + - name: Deploy Frontend to Remote Server + uses: appleboy/ssh-action@v0.1.7 + with: + host: ${{ secrets.SERVER_IP }} + username: ${{ secrets.SSH_USERNAME }} + password: ${{ secrets.SSH_PASSWORD }} + port: 22 + script: | + cd /srv/lenka-messenger + docker-compose -f docker-compose.prod.yaml up -d --no-deps lm-frontend \ No newline at end of file diff --git a/.gitignore b/.gitignore index 8627e50..7f75622 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,6 @@ # Logs /logs/ + +# Environment +.env \ No newline at end of file diff --git a/backend/Dockerfile b/backend/Dockerfile new file mode 100644 index 0000000..f33ddb7 --- /dev/null +++ b/backend/Dockerfile @@ -0,0 +1,3 @@ +FROM amazoncorretto:21-alpine-jdk +COPY target/*.jar lm-backend.jar +ENTRYPOINT ["java", "-jar", "/lm-backend.jar"] \ No newline at end of file diff --git a/backend/pom.xml b/backend/pom.xml index 79ef988..3b7b262 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -25,14 +25,14 @@ org.springframework.boot spring-boot-starter-actuator - - - - - - - - + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-security + org.springframework.boot spring-boot-starter-web @@ -42,11 +42,11 @@ spring-boot-starter-websocket - - - - - + + org.postgresql + postgresql + runtime + org.projectlombok lombok diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index 286afee..62c3ecf 100644 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties @@ -1 +1,12 @@ +server.port=8080 spring.application.name=lenka-messenger + +spring.jpa.hibernate.ddl-auto=none +spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect +spring.jpa.properties.hibernate.format_sql=true +spring.sql.init.mode=always + +spring.datasource.driverClassName=org.postgresql.Driver +spring.datasource.url=${SPRING_DATASOURCE_URL} +spring.datasource.username=${POSTGRES_USER} +spring.datasource.password=${POSTGRES_PASSWORD} \ No newline at end of file diff --git a/docker-compose.dev.yaml b/docker-compose.dev.yaml new file mode 100644 index 0000000..8264936 --- /dev/null +++ b/docker-compose.dev.yaml @@ -0,0 +1,58 @@ +version: '3.9' + +services: + lm-backend: + build: + context: ./backend + container_name: lm-backend + ports: + - "8080:8080" + depends_on: + - postgres + environment: + - SPRING_DATASOURCE_URL=jdbc:postgresql://postgres:5432/lenkamessenger + - POSTGRES_USER=postgres + - POSTGRES_PASSWORD=postgres + networks: + - app-network + restart: unless-stopped + + lm-frontend: + build: + context: ./frontend + container_name: lm-frontend + ports: + - "3000:80" + networks: + - app-network + restart: unless-stopped + + postgres: + image: postgres:14-alpine + container_name: postgres + ports: + - "6551:5432" + volumes: + - /var/lib/postgresql/data + environment: + - POSTGRES_DB=lenkamessenger + - POSTGRES_USER=postgres + - POSTGRES_PASSWORD=postgres + - TZ=GMT + networks: + - app-network + + pgadmin: + image: dpage/pgadmin4 + container_name: pgadmin + environment: + PGADMIN_DEFAULT_EMAIL: admin@admin.ru + PGADMIN_DEFAULT_PASSWORD: admin + ports: + - "5050:80" + networks: + - app-network + +networks: + app-network: + driver: bridge \ No newline at end of file diff --git a/docker-compose.prod.yaml b/docker-compose.prod.yaml new file mode 100644 index 0000000..198fdd3 --- /dev/null +++ b/docker-compose.prod.yaml @@ -0,0 +1,56 @@ +version: '3.9' + +services: + lm-backend: + image: nickpominov/lm-backend:latest + container_name: lm-backend + ports: + - "8080:8080" + depends_on: + - postgres + environment: + - SPRING_DATASOURCE_URL=jdbc:postgresql://postgres:5432/lenkamessenger + - POSTGRES_USER=${POSTGRES_USER} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} + networks: + - app-network + restart: unless-stopped + + lm-frontend: + image: nickpominov/lm-frontend:latest + container_name: lm-frontend + ports: + - "3000:80" + networks: + - app-network + restart: unless-stopped + + postgres: + image: postgres:14-alpine + container_name: postgres + ports: + - "6551:5432" + volumes: + - /srv/postgresql-data:/var/lib/postgresql/data + environment: + - POSTGRES_DB=lenkamessenger + - POSTGRES_USER=${POSTGRES_USER} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} + - TZ=GMT + networks: + - app-network + + pgadmin: + image: dpage/pgadmin4 + container_name: pgadmin + environment: + PGADMIN_DEFAULT_EMAIL: ${PGADMIN_DEFAULT_EMAIL} + PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_DEFAULT_PASSWORD} + ports: + - "5050:80" + networks: + - app-network + +networks: + app-network: + driver: bridge \ No newline at end of file diff --git a/frontend/Dockerfile b/frontend/Dockerfile new file mode 100644 index 0000000..39ba972 --- /dev/null +++ b/frontend/Dockerfile @@ -0,0 +1,3 @@ +FROM caddy:alpine +COPY ./dist /usr/share/caddy +EXPOSE 80 \ No newline at end of file diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 8f3e196..2427ae6 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -1,6 +1,6 @@