Skip to content
Open
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
58 changes: 58 additions & 0 deletions .github/workflows/Test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle

name: 릿츠 블로그 테스트 CI 파이프라인

### develop으로 PR 올릴 때, 테스트 코드를 실행하여, 체크하는 로직을 수행한다.

on:
pull_request:
branches: ["이도연/main","이도연/6주차"]

jobs:
#1. Test 용
test:

runs-on: ubuntu-22.04
permissions:
contents: write
checks: write
pull-requests: write

steps:
# 1-1. repository checkout
- uses: actions/checkout@v4

# 1-2. jdk 환경 설치
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'

# 3. '*.yml' 파일 세팅
- name: application.yml 파일 설정
run: |
mkdir -p src/main/resources
echo "${{ secrets.APPLICATION_YML }}" > ./src/main/resources/application.yml

# 1-4. gradle 환경 설치
- name: Setup Gradle
uses: gradle/actions/setup-gradle@af1da67850ed9a4cedd57bfd976089dd991e2582 # v4.0.0

# 1-5. 빌드
- name: Build with Gradle Wrapper
run: ./gradlew build

# 7. JUnit 테스트 결과 게시
- name: Test 결과 출력
uses: EnricoMi/publish-unit-test-result-action@v2
if: always()
with:
junit_files: '**/build/test-results/test/TEST-*.xml'
github_token: ${{ secrets.GITHUB_TOKEN }}

122 changes: 122 additions & 0 deletions .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle

name: 릿츠 블로그 CI-CD 파이프라인

on:
push:
branches: [ "이도연/main" ,"이도연/6주차"]

jobs:
#1. 개발 서버 CI, Build 용
CI:
runs-on: ubuntu-22.04
permissions:
contents: write
checks: write
pull-requests: write

steps:
# 1. repository checkout
- uses: actions/checkout@v4

# 2. jdk 환경 설치
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'

# 3. '*.yml' 파일 세팅
- name: application.yml 파일 설정
run: |
mkdir -p src/main/resources
echo "${{ secrets.APPLICATION_YML }}" > ./src/main/resources/application.yml

# 4. gradle 환경 설치
- name: Gradle Wrapper 권한 부여
run: chmod +x gradlew

# 4-1. 캐싱
- name: Gradle Caching
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
gradle-${{ runner.os }}

- name: Gradle 빌드
run: ./gradlew clean build

# 6. JUnit 테스트 결과 게시
- name: Test 결과 출력
uses: EnricoMi/publish-unit-test-result-action@v2
if: always()
with:
junit_files: '**/build/test-results/test/TEST-*.xml'
github_token: ${{ secrets.GITHUB_TOKEN }}

#7. 도커 허브 로그인
- name: Docker 로그인
uses: docker/login-action@v3
with:
username: ${{secrets.DOCKER_USERNAME}}
password: ${{secrets.DOCKER_ACCESS_TOKEN}}

#8. 도커 이미지 Push
- name: Docker 이미지 Push
uses: docker/build-push-action@v5
with:
context: .
dockerfile: Dockerfile
push: true
tags: ${{secrets.DOCKER_USERNAME}}/leets:latest

CD:
needs: CI
runs-on: ubuntu-22.04

steps:
- name: 1. Checkout source code
uses: actions/checkout@v3

- name: env 생성
run: echo "${{ secrets.ENV }}" > .env

- name: 2. .env 파일 EC2에 전송
uses: appleboy/scp-action@master
with:
host: ${{ secrets.EC2_PUBLIC_IP }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.EC2_PRIVATE_KEY }}
source: ".env" # 방금 생성한 .env 파일
target: "/home/ubuntu/app/docker/"

- name: 3. docker-compose.yml 전달
uses: appleboy/scp-action@master
with:
host: ${{ secrets.EC2_PUBLIC_IP }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.EC2_PRIVATE_KEY }}
source: "./docker/docker-compose.yml"
target: "/home/ubuntu/app/"

- name: 3. EC2에서 docker-compose 실행
uses: appleboy/ssh-action@master # SSH를 사용하여 EC2에서 명령 실행
with:
host: ${{ secrets.EC2_PUBLIC_IP }} # EC2 퍼블릭 IP
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.EC2_PRIVATE_KEY }}
script: |
# docker-compose 명령어 실행
cd /home/ubuntu/app/docker/
docker compose pull spring
docker compose up -d spring

12 changes: 12 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# 1. JDK 이미지를 베이스로 설정
FROM eclipse-temurin:17-jdk

# 2. 작업 디렉토리 설정
WORKDIR /app

# 3. jar 파일 복사
ARG JAR_FILE=build/libs/blog-0.0.1-SNAPSHOT.jar
COPY ${JAR_FILE} app.jar

# 4. 실행
ENTRYPOINT ["java", "-jar", "app.jar"]
6 changes: 5 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ version = '0.0.1-SNAPSHOT'

java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
languageVersion = JavaLanguageVersion.of(17)
}
}

Expand All @@ -31,6 +31,10 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
runtimeOnly 'com.mysql:mysql-connector-j'

// s3
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'


// test
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
Expand Down
19 changes: 18 additions & 1 deletion docker/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,26 @@
services:

spring:
image: eedoy/leets:latest
container_name: leets-app
ports:
- "8080:8080"
depends_on:
- mysql
networks:
- backend-bridge

mysql:
image: mysql:8.0
container_name: leets-mysql
restart: always
env_file:
- .env
ports:
- "3306:3306"
- "3306:3306"
networks:
- backend-bridge

networks:
backend-bridge:
driver: bridge
34 changes: 34 additions & 0 deletions src/main/java/com/blog/common/config/S3Config.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.blog.common.config;

import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class S3Config {
@Value("${cloud.aws.credentials.access-key}")
private String accessKey;

@Value("${cloud.aws.credentials.secret-key}")
private String secretKey;

@Value("${cloud.aws.region.static}")
private String region;

@Bean
public AmazonS3 amazonS3() {
AWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);

return AmazonS3ClientBuilder
.standard()
.withCredentials(new AWSStaticCredentialsProvider(credentials))
.withRegion(region)
.build();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,17 @@
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;

@RestController
@RequestMapping("/auth")
public class AuthController {

private static final Logger log = LoggerFactory.getLogger(AuthController.class);
// 자체 회원가입
private final RegisterUserUseCase registerService;

Expand All @@ -36,7 +41,7 @@ public AuthController(RegisterUserUseCase registerService, AuthUserUseCase authS

/// 자체 회원가입 기능
@PostMapping
public ApiResponse<String> register(@RequestBody @Valid UserRegisterRequest request) {
public ApiResponse<String> register(@ModelAttribute UserRegisterRequest request) throws IOException {

registerService.registerUser(request);
return ApiResponse.ok("회원 가입 성공했습니다.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;

@RestController
@RequestMapping("/posts")
public class PostController {
Expand All @@ -24,7 +26,7 @@ public PostController(PostUseCase postService) {

// 게시글 작성
@PostMapping
ApiResponse<String> createPost(@RequestUserId Long userId, @RequestBody @Valid PostRequest postRequest) {
ApiResponse<String> createPost(@RequestUserId Long userId, @ModelAttribute @Valid PostRequest postRequest) throws IOException {

postService.savePost(postRequest, userId);

Expand Down Expand Up @@ -52,7 +54,7 @@ ApiResponse<Page<PostListResponse>> getPostList(@RequestParam(required = false,

// 게시글 수정
@PutMapping("/{postId}")
ApiResponse<String> updatePost(@RequestUserId Long userId, @PathVariable Long postId, @RequestBody PostUpdateRequest request) {
ApiResponse<String> updatePost(@RequestUserId Long userId, @PathVariable Long postId, @ModelAttribute PostUpdateRequest request) throws IOException {

postService.updatePost(postId, userId, request);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import com.blog.workspace.domain.user.User;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;

@RestController
@RequestMapping("/users")
public class UserController {
Expand All @@ -31,7 +33,7 @@ public ApiResponse<UserResponse> getMyInfo(@RequestUserId Long userId) {
}

@PutMapping()
public ApiResponse<String> updateMyInfo(@RequestUserId Long userId, @RequestBody UserUpdateRequest request) {
public ApiResponse<String> updateMyInfo(@RequestUserId Long userId, @ModelAttribute UserUpdateRequest request) throws IOException {

updateService.updateUser(userId, request);
return ApiResponse.ok("수정되었습니다.");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
package com.blog.workspace.adapter.in.web.dto.request;

import com.blog.workspace.domain.post.ContentType;
import org.springframework.web.multipart.MultipartFile;

public class ContentRequest {

private ContentType type;
private String content;
private MultipartFile image;

public ContentRequest(ContentType type, String content, MultipartFile image) {
this.type = type;
this.content = content;
this.image = image;
}

/// @Getter
public ContentType getType() {
Expand All @@ -15,4 +23,8 @@ public ContentType getType() {
public String getContent() {
return content;
}

public MultipartFile getImage() {
return image;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ public class PostRequest {
@NotNull(message = "글 작성은 필수입니다.")
private List<ContentRequest> content;

public PostRequest(String title, List<ContentRequest> content) {
this.title = title;
this.content = content;
}

public String getTitle() {
return title;
}
Expand Down
Loading