Skip to content

Commit d45dfb0

Browse files
authored
Merge pull request #17 from prgrms-web-devcourse-final-project/develop
Test: AWS 배포 테스트 위한 임시 PR
2 parents 428fed3 + be32ba0 commit d45dfb0

File tree

75 files changed

+2822
-3
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

75 files changed

+2822
-3
lines changed

.github/scripts/code_review.py

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
import os
2+
import requests
3+
import json
4+
import re
5+
from github import Github
6+
from collections import defaultdict
7+
from concurrent.futures import ThreadPoolExecutor, as_completed
8+
9+
def get_changed_files(pr):
10+
changed_files = []
11+
for file in pr.get_files():
12+
if file.filename.endswith('.java'):
13+
changed_files.append({
14+
'filename': file.filename,
15+
'patch': file.patch,
16+
'status': file.status,
17+
})
18+
return changed_files
19+
20+
def get_file_content(repo, file_path, ref):
21+
return repo.get_contents(file_path, ref=ref).decoded_content.decode('utf-8')
22+
23+
def search_file(repo, file, changed_files, ref):
24+
if file.type == 'file' and file.name.endswith('.java'):
25+
content = get_file_content(repo, file.path, ref)
26+
related = set()
27+
for changed_file in changed_files:
28+
changed_name = os.path.splitext(os.path.basename(changed_file['filename']))[0]
29+
if re.search(r'\b' + re.escape(changed_name) + r'\b', content):
30+
related.add(changed_file['filename'])
31+
return file.path, related
32+
return None, set()
33+
34+
def find_related_files(repo, changed_files, ref):
35+
related_files = defaultdict(set)
36+
all_files = repo.get_contents('', ref=ref)
37+
dirs_to_process = [file for file in all_files if file.type == 'dir']
38+
39+
with ThreadPoolExecutor(max_workers=10) as executor:
40+
future_to_file = {executor.submit(search_file, repo, file, changed_files, ref): file for file in all_files if file.type == 'file'}
41+
42+
while dirs_to_process:
43+
dir_files = repo.get_contents(dirs_to_process.pop().path, ref=ref)
44+
dirs_to_process.extend([file for file in dir_files if file.type == 'dir'])
45+
future_to_file.update({executor.submit(search_file, repo, file, changed_files, ref): file for file in dir_files if file.type == 'file'})
46+
47+
for future in as_completed(future_to_file):
48+
file_path, related = future.result()
49+
if related:
50+
for changed_file in related:
51+
related_files[changed_file].add(file_path)
52+
53+
return related_files
54+
55+
56+
def call_claude_api(changes, related_files):
57+
url = "https://api.anthropic.com/v1/messages"
58+
headers = {
59+
"Content-Type": "application/json",
60+
"x-api-key": os.environ['CLAUDE_API_KEY'],
61+
"anthropic-version": "2023-06-01"
62+
}
63+
64+
system_content = (
65+
"경험 많은 시니어 개발자로서, 다음 변경사항들에 대해 전체적이고 간결한 코드 리뷰를 수행해주세요.\n\n"
66+
"리뷰 지침:\n"
67+
"1. 모든 변경사항을 종합적으로 검토하고, 가장 중요한 문제점이나 개선사항에만 집중하세요.\n"
68+
"2. 파일별로 개별 리뷰를 하지 말고, 전체 변경사항에 대한 통합된 리뷰를 제공하세요.\n"
69+
"3. 각 주요 이슈에 대해 간단한 설명과 구체적인 개선 제안을 제시하세요.\n"
70+
"4. 개선 제안에는 실제 코드 예시를 포함하세요. 단, 코드 예시는 제공한 코드와 연관된 코드여야 합니다. \n"
71+
"5. 사소한 스타일 문제나 개인적 선호도는 무시하세요.\n"
72+
"6. 심각한 버그, 성능 문제, 또는 보안 취약점이 있는 경우에만 언급하세요.\n"
73+
"7. 전체 리뷰는 간결하게 유지하세요.\n"
74+
"8. 변경된 부분만 집중하여 리뷰하고, 이미 개선된 코드를 다시 지적하지 마세요.\n"
75+
"9. 기존에 이미 개선된 사항(예: 중복 코드 제거를 위한 함수 생성)을 인식하고 이를 긍정적으로 언급하세요.\n"
76+
"10. 변경된 파일과 관련된 다른 파일들에 미칠 수 있는 영향을 분석하세요.\n\n"
77+
"리뷰 형식:\n"
78+
"- 개선된 사항: [이미 개선된 부분에 대한 긍정적 언급]\n"
79+
"- 주요 이슈 (있는 경우에만):\n"
80+
" 1. [문제 설명]\n"
81+
" - 제안: [개선 방안 설명]\n"
82+
" ```java\n"
83+
" // 수정된 코드 예시\n"
84+
" ```\n"
85+
" 2. ...\n"
86+
"- 관련 파일에 대한 영향 분석:\n"
87+
" [변경된 파일과 관련된 다른 파일들에 미칠 수 있는 잠재적 영향 설명]\n"
88+
"- 전반적인 의견: [1-2문장으로 요약]\n\n"
89+
"변경된 파일들:\n"
90+
)
91+
92+
for file_info in changes:
93+
system_content += f"- {file_info['filename']} ({file_info['status']})\n"
94+
95+
system_content += "\n변경 내용:\n"
96+
for file_info in changes:
97+
system_content += f"파일: {file_info['filename']}\n전체 내용:\n{file_info['full_content']}\n\n변경된 부분:\n{file_info['patch']}\n\n"
98+
99+
system_content += "\n관련된 파일들:\n"
100+
for changed_file, related in related_files.items():
101+
system_content += f"- {changed_file}에 영향을 받을 수 있는 파일들:\n"
102+
for related_file in related:
103+
system_content += f" - {related_file}\n"
104+
105+
payload = {
106+
"model": "claude-3-5-sonnet-20240620",
107+
"max_tokens": 2000,
108+
"system": system_content,
109+
"messages": [
110+
{
111+
"role": "user",
112+
"content": [
113+
{
114+
"type": "text",
115+
"text": "제공된 모든 변경사항에 대해 통합된, 간결하고 핵심적인 코드 리뷰를 제공해주세요. 가장 중요한 이슈에만 집중하고, 각 개선 제안에는 구체적인 코드 예시를 포함해주세요. 변경된 부분만 집중하여 리뷰하고, 이미 개선된 코드를 다시 지적하지 마세요. 또한, 변경된 파일과 관련된 다른 파일들에 미칠 수 있는 잠재적 영향을 분석해주세요."
116+
}
117+
]
118+
}
119+
]
120+
}
121+
122+
response = requests.post(url, headers=headers, json=payload)
123+
if response.status_code == 200:
124+
return response.json()['content'][0]['text']
125+
else:
126+
return f"Error: API returned status code {response.status_code}"
127+
128+
def main():
129+
g = Github(os.environ['GITHUB_TOKEN'])
130+
repo = g.get_repo(os.environ['GITHUB_REPOSITORY'])
131+
pr_number = int(os.environ['PR_NUMBER'])
132+
pr = repo.get_pull(pr_number)
133+
134+
changed_files = get_changed_files(pr)
135+
changes = []
136+
137+
for file_info in changed_files:
138+
full_content = get_file_content(repo, file_info['filename'], pr.head.sha)
139+
file_info['full_content'] = full_content
140+
changes.append(file_info)
141+
142+
related_files = find_related_files(repo, changed_files, pr.head.sha)
143+
review = call_claude_api(changes, related_files)
144+
145+
pr.create_issue_comment(f"Claude의 전체 변경사항 및 관련 파일에 대한 리뷰:\n\n{review}")
146+
147+
if __name__ == "__main__":
148+
main()

.github/scripts/deploy.sh

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#!/bin/bash
2+
3+
PROJECT_ROOT="/home/ubuntu/build"
4+
JAR_FILE="$PROJECT_ROOT/spring-log4u.jar"
5+
6+
APP_LOG="$PROJECT_ROOT/application.log"
7+
ERROR_LOG="$PROJECT_ROOT/error.log"
8+
DEPLOY_LOG="$PROJECT_ROOT/deploy.log"
9+
10+
TIME_NOW=$(date +%c)
11+
12+
# build 파일 복사
13+
echo "$TIME_NOW > $JAR_FILE 파일 복사" >> $DEPLOY_LOG
14+
cp $PROJECT_ROOT/build/libs/*.jar $JAR_FILE
15+
16+
# jar 파일 실행
17+
echo "$TIME_NOW > $JAR_FILE 파일 실행" >> $DEPLOY_LOG
18+
nohup java -jar $JAR_FILE > $APP_LOG 2> $ERROR_LOG &
19+
20+
CURRENT_PID=$(pgrep -f $JAR_FILE)
21+
echo "$TIME_NOW > 실행된 프로세스 아이디 $CURRENT_PID 입니다." >> $DEPLOY_LOG

.github/scripts/stop.sh

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#!/usr/bin/env bash
2+
3+
PROJECT_ROOT="/home/ubuntu/build"
4+
JAR_FILE="$PROJECT_ROOT/spring-log4u.jar"
5+
6+
DEPLOY_LOG="$PROJECT_ROOT/deploy.log"
7+
8+
TIME_NOW=$(date +%c)
9+
10+
# 현재 구동 중인 애플리케이션 pid 확인
11+
CURRENT_PID=$(pgrep -f $JAR_FILE)
12+
13+
# 프로세스가 켜져 있으면 종료
14+
if [ -z $CURRENT_PID ]; then
15+
echo "$TIME_NOW > 현재 실행중인 애플리케이션이 없습니다" >> $DEPLOY_LOG
16+
else
17+
echo "$TIME_NOW > 실행중인 $CURRENT_PID 애플리케이션 종료 " >> $DEPLOY_LOG
18+
kill -15 $CURRENT_PID
19+
fi

.github/workflows/build.yml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
name: log4u-build
2+
on:
3+
# push:
4+
# branches:
5+
# - develop # dev 브랜치 push
6+
pull_request:
7+
branches:
8+
- main # main pr
9+
- develop # develop pr
10+
types: [ opened, synchronize, reopened ]
11+
jobs:
12+
build:
13+
name: Build and analyze
14+
runs-on: ubuntu-latest
15+
steps:
16+
- uses: actions/checkout@v4
17+
with:
18+
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
19+
- name: Set up JDK 21
20+
uses: actions/setup-java@v4
21+
with:
22+
java-version: 21
23+
distribution: 'zulu' # Alternative distribution options are available
24+
- name: Cache Gradle packages
25+
uses: actions/cache@v4
26+
with:
27+
path: ~/.gradle/caches
28+
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
29+
restore-keys: ${{ runner.os }}-gradle
30+
- name: Cache SonarCloud packages
31+
uses: actions/cache@v4
32+
with:
33+
path: ~/.sonar/cache
34+
key: ${{ runner.os }}-sonar
35+
restore-keys: ${{ runner.os }}-sonar
36+
- name: Build and analyze
37+
env:
38+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
39+
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
40+
DB_URL: ${{ secrets.DB_URL }} # Database URL
41+
DB_USERNAME: ${{ secrets.DB_USERNAME }} # Database username
42+
DB_PASSWORD: ${{ secrets.DB_PASSWORD }} # Database password
43+
run: |
44+
chmod +x ./gradlew
45+
./gradlew build jacocoTestReport sonar --info -Dsonar.branch.name=${{ github.ref_name }}

.github/workflows/ci.cd.prod.yml

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
name: Deploy workflow on production environment
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- main
7+
types:
8+
- closed
9+
workflow_dispatch: # 수동 실행 가능
10+
11+
12+
# 병합됐을 때
13+
jobs:
14+
deploy:
15+
runs-on: ubuntu-latest
16+
steps:
17+
# 체크아웃
18+
- uses: actions/checkout@v4
19+
20+
# AWS 인증 (IAM 사용자 Access Key, Secret Key 활용)
21+
- name: Configure AWS credentials
22+
uses: aws-actions/configure-aws-credentials@v1
23+
with:
24+
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
25+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
26+
aws-region: ${{ secrets.AWS_REGION }}
27+
28+
# Gradle 권한 설정
29+
- name: Grant execute permission for gradlew
30+
run: chmod +x ./gradlew
31+
32+
# JDK 21 세팅
33+
- name: Set up JDK 21
34+
uses: actions/setup-java@v4
35+
with:
36+
java-version: 21
37+
distribution: 'temurin'
38+
39+
# Gradle cache 설정
40+
- name: Cache Gradle packages
41+
uses: actions/cache@v4
42+
with:
43+
path: ~/.gradle/caches
44+
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
45+
restore-keys: ${{ runner.os }}-gradle
46+
47+
# Gradle build (우선 Test 제외)
48+
- name: Build with Gradle
49+
uses: gradle/gradle-build-action@0d13054264b0bb894ded474f08ebb30921341cee
50+
with:
51+
arguments: clean build -x test
52+
53+
54+
# 빌드 결과물을 S3 버킷에 업로드
55+
- name: Upload to AWS S3
56+
run: |
57+
aws deploy push \
58+
--application-name ${{ secrets.CODE_DEPLOY_APP_NAME }} \
59+
--ignore-hidden-files \
60+
--s3-location s3://$S3_BUCKET_NAME/$GITHUB_SHA.zip \
61+
--source .
62+
63+
# S3 버킷에 있는 파일을 대상으로 CodeDeploy 실행
64+
- name: Deploy to AWS EC2 from S3
65+
run: |
66+
aws deploy create-deployment \
67+
--application-name ${{ secrets.CODE_DEPLOY_APP_NAME }} \
68+
--deployment-config-name CodeDeployDefault.AllAtOnce \
69+
--deployment-group-name ${{ secrets.CODE_DEPLOY_DEPLOYMENT_GROUP_NAME }} \
70+
--s3-location bucket=$S3_BUCKET_NAME,key=$GITHUB_SHA.zip,bundleType=zip
71+
72+
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
name: Code Review from Claude
2+
3+
on:
4+
pull_request:
5+
types: [opened, synchronize]
6+
7+
permissions:
8+
contents: read
9+
pull-requests: write
10+
11+
jobs:
12+
review:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v2
16+
with:
17+
fetch-depth: 0
18+
19+
- name: Set up Python
20+
uses: actions/setup-python@v2
21+
with:
22+
python-version: '3.x'
23+
24+
- name: Install dependencies
25+
run: |
26+
python -m pip install --upgrade pip
27+
pip install requests PyGithub
28+
29+
- name: Run Code Review
30+
env:
31+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
32+
CLAUDE_API_KEY: ${{ secrets.CLAUDE_API_KEY }}
33+
PR_NUMBER: ${{ github.event.pull_request.number }}
34+
run: python .github/scripts/code_review.py

0 commit comments

Comments
 (0)