Skip to content

Develop #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Aug 23, 2024
Merged
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
140 changes: 140 additions & 0 deletions .github/workflows/CICD.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
name: CICD

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]

permissions:
contents: read

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'

- name: Create application-secret-deploy.yml
run: |
echo "Decoding SECRET_FILE secret and create application-secret-deploy.yml"
echo "${{ secrets.SECRET_FILE }}" | base64 -d > ./src/main/resources/application-secret-deploy.yml


- name: Build with Gradle
run: |
chmod 777 ./gradlew
./gradlew clean assemble -x test

- name: Login to DockerHub
if: github.event_name == 'push'
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Build Docker
if: github.event_name == 'push'
run: docker build --platform linux/amd64 -t ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPO_NAME }} .

- name: Push Docker
if: github.event_name == 'push'
run: docker push ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPO_NAME }}:latest

deploy:
needs: build
if: github.event_name == 'push'
runs-on: ubuntu-latest
steps:
- name: Set target IP
run: |
STATUS=$(curl -o /dev/null -w "%{http_code}" "http://${{ secrets.LIVE_SERVER_IP }}/env")
echo $STATUS
if [ $STATUS = 200 ]; then
CURRENT_UPSTREAM=$(curl -s "http://${{ secrets.LIVE_SERVER_IP }}/env")
else
CURRENT_UPSTREAM=green
fi
echo CURRENT_UPSTREAM=$CURRENT_UPSTREAM >> $GITHUB_ENV
if [ $CURRENT_UPSTREAM = blue ]; then
echo "CURRENT_PORT=8080" >> $GITHUB_ENV
echo "STOPPED_PORT=8081" >> $GITHUB_ENV
echo "TARGET_UPSTREAM=green" >> $GITHUB_ENV
elif [ $CURRENT_UPSTREAM = green ]; then
echo "CURRENT_PORT=8081" >> $GITHUB_ENV
echo "STOPPED_PORT=8080" >> $GITHUB_ENV
echo "TARGET_UPSTREAM=blue" >> $GITHUB_ENV
else
echo "error"
exit 1
fi

- name: Login Server
uses: appleboy/ssh-action@master
with:
username: ${{ secrets.SERVER_USER_NAME }}
host: ${{ secrets.LIVE_SERVER_IP }}
key: ${{ secrets.SSH_KEY }}
script_stop: true

- name: Docker compose
uses: appleboy/ssh-action@master
with:
username: ${{ secrets.SERVER_USER_NAME }}
host: ${{ secrets.LIVE_SERVER_IP }}
key: ${{ secrets.SSH_KEY }}
script_stop: true
script: |
sudo docker pull ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPO_NAME }}:latest
sudo docker-compose -f docker-compose-${{env.TARGET_UPSTREAM}}.yml up -d

- name: Check deploy server URL
uses: jtalk/url-health-check-action@v3
with:
url: http://${{ secrets.LIVE_SERVER_IP }}:${{env.STOPPED_PORT}}/env
max-attempts: 5
retry-delay: 10s

- name: Change nginx upstream
uses: appleboy/ssh-action@master
with:
username: ${{ secrets.SERVER_USER_NAME }}
host: ${{ secrets.LIVE_SERVER_IP }}
key: ${{ secrets.SSH_KEY }}
script_stop: true
script: |
sudo docker exec -i nginxserver bash -c 'echo "set \$service_url ${{ env.TARGET_UPSTREAM }};" > /etc/nginx/conf.d/service-env.inc && nginx -s reload'

- name: Stop current server
uses: appleboy/ssh-action@master
with:
username: ${{ secrets.SERVER_USER_NAME }}
host: ${{ secrets.LIVE_SERVER_IP }}
key: ${{ secrets.SSH_KEY }}
script_stop: true
script: |
if [ $(sudo docker ps -a -q -f name=${{env.CURRENT_UPSTREAM}}) ]; then
sudo docker stop ${{env.CURRENT_UPSTREAM}}
sudo docker rm ${{env.CURRENT_UPSTREAM}}
else
echo "Container ${{env.CURRENT_UPSTREAM}} does not exist, skipping stop and remove steps."
fi

- name: Delete old docker images
uses: appleboy/ssh-action@master
with:
username: ${{ secrets.SERVER_USER_NAME }}
host: ${{ secrets.LIVE_SERVER_IP }}
key: ${{ secrets.SSH_KEY }}
script: |
dangling_images=$(sudo docker images -f "dangling=true" -q)
if [ ! -z "$dangling_images" ]; then
sudo docker rmi $dangling_images
else
echo "No dangling images found"
fi
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/
!**/src/main/resoureces/application.yml
application-*.yml

### STS ###
.apt_generated
Expand Down Expand Up @@ -38,4 +40,5 @@ out/


### SET ###
!**/src/main/resources/application.properties
application.properties
application.yml
6 changes: 6 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
FROM amazoncorretto:17-alpine-jdk
ARG JAR_FILE=build/libs/*.jar
ARG PROFILES
ARG ENV
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java", "-Dspring.profiles.active=${PROFILES}", "-Dserver.env=${ENV}", "-jar", "app.jar"]
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ repositories {

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
implementation 'org.springframework.boot:spring-boot-starter-security'
// implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
// implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.mysql:mysql-connector-j'
Expand Down
2 changes: 1 addition & 1 deletion settings.gradle
Original file line number Diff line number Diff line change
@@ -1 +1 @@
rootProject.name = 'main'
rootProject.name = 'code-view'
65 changes: 65 additions & 0 deletions src/main/java/codeview/main/controller/BoardController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package codeview.main.controller;

import codeview.main.dto.ApiResponse;
import codeview.main.dto.BoardRequest;
import codeview.main.dto.BoardResponse;
import codeview.main.entity.Board;
import codeview.main.service.BoardService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.Optional;


@RestController
@RequiredArgsConstructor
@RequestMapping("/board")
public class BoardController {
private final BoardService boardService;
@GetMapping("/{id}")
public ResponseEntity<BoardResponse> getBoardById(@PathVariable Long id) {
Optional<Board> findBoardObj = boardService.findBoardById(id);
if (findBoardObj.isPresent()) {
BoardResponse response = new BoardResponse(findBoardObj.get());
return ResponseEntity.ok(response);
} else {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
}
}

@PostMapping("/write")
public ResponseEntity<ApiResponse<BoardResponse>> boardSave(@RequestBody Board board) {
Board saveBoard = boardService.save(board);
BoardResponse boardResponse = new BoardResponse(saveBoard);
ApiResponse<BoardResponse> response = new ApiResponse<>(HttpStatus.CREATED, "Board Write Success", boardResponse);
return ResponseEntity.status(HttpStatus.CREATED)
.body(response);
}
@PutMapping("/{id}")
public ResponseEntity<BoardResponse> updateBoard(
@PathVariable Long id,
@RequestBody BoardRequest boardRequest) {
Board updatedBoard = new Board();
updatedBoard.setTitle(boardRequest.getTitle());

try {
Board savedBoard = boardService.updateBoard(id, updatedBoard);
BoardResponse responseDto = new BoardResponse(savedBoard);
return ResponseEntity.ok(responseDto);
} catch (RuntimeException e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
}
}

@DeleteMapping("/{id}")
public ResponseEntity<BoardResponse> deleteBoard(@PathVariable Long id) {
try {
boardService.deleteBoard(id);
return ResponseEntity.noContent().build();
}catch (RuntimeException e){
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package codeview.main.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;
import java.util.TreeMap;

@RestController
public class ServerHealthCheckController {
@Value("${server.env}")
private String env;
@Value("${server.port}")
private String serverPort;
@Value("${server.serverAddress}")
private String serverAddress;
@Value("${serverName}")
private String serverName;

@GetMapping("/hc")
public ResponseEntity<?> healthCheck() {
Map<String, String> responseData = new TreeMap<>();
responseData.put("serverName", serverName);
responseData.put("serverAddress", serverAddress);
responseData.put("serverPort", serverPort);
responseData.put("env", env);
return ResponseEntity.ok(responseData);
}

@GetMapping("/env")
@ResponseBody
public ResponseEntity<?> getEnv() {
return ResponseEntity.ok().body(env);
}
}
20 changes: 20 additions & 0 deletions src/main/java/codeview/main/dto/ApiResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package codeview.main.dto;


import lombok.Getter;
import lombok.Setter;
import org.springframework.http.HttpStatus;

@Getter
@Setter
public class ApiResponse<T> {
private HttpStatus httpStatus;
private String message;
private T data;

public ApiResponse(HttpStatus httpStatus, String message, T data) {
this.httpStatus = httpStatus;
this.message = message;
this.data = data;
}
}
9 changes: 9 additions & 0 deletions src/main/java/codeview/main/dto/BoardRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package codeview.main.dto;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class BoardRequest {
private String title;
}
17 changes: 17 additions & 0 deletions src/main/java/codeview/main/dto/BoardResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package codeview.main.dto;

import codeview.main.entity.Board;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class BoardResponse {
private Long id;
private String title;

public BoardResponse(Board board) {
this.id = board.getId();
this.title = board.getTitle();
}
}
25 changes: 25 additions & 0 deletions src/main/java/codeview/main/entity/Board.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package codeview.main.entity;

import jakarta.persistence.*;
import lombok.*;

import java.util.List;

@Entity
@Getter @Setter
@NoArgsConstructor
public class Board {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;
@Column
private String title;
//
// @Column @OneToOne
// private Content content;
//
// @Column @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
// private List<Comment> commentList;

public Board(String title) {
this.title = title;
}
}
10 changes: 10 additions & 0 deletions src/main/java/codeview/main/entity/Comment.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package codeview.main.entity;

import jakarta.persistence.Entity;
import jakarta.persistence.Id;

@Entity
public class Comment {
@Id
private Long id;
}
12 changes: 12 additions & 0 deletions src/main/java/codeview/main/entity/Content.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package codeview.main.entity;


import jakarta.persistence.Entity;
import jakarta.persistence.Id;

@Entity
public class Content {
@Id
private Long id;

}
9 changes: 9 additions & 0 deletions src/main/java/codeview/main/repository/BoardRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package codeview.main.repository;

import codeview.main.entity.Board;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface BoardRepository extends JpaRepository<Board, Long> {
}
Loading
Loading