Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
1be2a6c
chore: chatgpt 연동
sapiens2000 Mar 25, 2025
b3af25f
fix: 연동 오류 수정
sapiens2000 Mar 25, 2025
49804d1
Merge pull request #1 from prgrms-web-devcourse-final-project/feature…
sapiens2000 Mar 25, 2025
b454e12
Chore: 메인 PR 시 코드 정적 검사, 테스트 실행
sapiens2000 Mar 25, 2025
f421a2f
Chore: 데일리 아카이빙 yml 파일 추가
sapiens2000 Mar 25, 2025
7f8bd7f
Chore: Dev 브랜치 push 옵션 제거
sapiens2000 Mar 25, 2025
2d10eda
Merge pull request #2 from prgrms-web-devcourse-final-project/feature…
sapiens2000 Mar 25, 2025
7830aee
chore: jacoco, sonarcloud, checkstyle 옵션 수정
sapiens2000 Mar 25, 2025
b9d2427
chore: 코드 정적 분석을 위한 파일 추가
sapiens2000 Mar 25, 2025
9432b27
Merge pull request #4 from prgrms-web-devcourse-final-project/feature…
sapiens2000 Mar 25, 2025
6e80989
feat: 전역 예외 처리 클래스(GlobalExceptionHandler) 구현
dnzp75 Mar 25, 2025
ec1a1cd
feat: 모든 도메인에서 사용할 공통 예외 인터페이스 및 ServiceException 구현
dnzp75 Mar 25, 2025
5dc474f
feat: 공통 예외 응답 클래스(ApiErrorResponse) 및 에러 코드 기반 구조 생성
dnzp75 Mar 25, 2025
82b3e2c
feat: 외부 API 호출에 대한 예외 처리 클래스 추가
dnzp75 Mar 25, 2025
ac43355
feat: RestTemplate용 ResponseErrorHandler 및 설정 클래스 추가
dnzp75 Mar 25, 2025
5c50c2d
feat: 도메인 예외 사용 예시로 Comment 도메인 Exception 구조 예시 추가
dnzp75 Mar 25, 2025
d03d624
feat: 테스트 시 401 상태 코드로 인한 스프링 시큐리티 설정 임시 주석 처리
dnzp75 Mar 25, 2025
08387f5
chore: gpt 모델 수정
sapiens2000 Mar 25, 2025
1626c9a
chore: gpt 권한 수정
sapiens2000 Mar 25, 2025
5551a8d
chore: claude 추가
sapiens2000 Mar 25, 2025
e3bc7c1
chore: ai 리뷰 위한 더미 커밋
sapiens2000 Mar 25, 2025
d991773
chore: 자바코드만 리뷰 하게 수정
sapiens2000 Mar 25, 2025
84b9643
feat: 좋아요 API에 대해 Diary domain 관련 필요한 클래스, Entity 추가
dnzp75 Mar 26, 2025
a186c06
feat: 좋아요 API에 대해 필요한 User domain 관련 Entity 추가
dnzp75 Mar 26, 2025
daebe25
feat: 좋아요 추가 API 구현
dnzp75 Mar 26, 2025
d4e9d39
feat: BaseEntity 추가 및 사용하기위한 @EnableJpaAuditing 추가
dnzp75 Mar 26, 2025
5a362f6
test: 단위 테스트 위한 Domain 별 Fixture 추가
dnzp75 Mar 26, 2025
e6bd210
test: 좋아요 추가 API 단위 테스트 작성
dnzp75 Mar 26, 2025
5e68a39
build: Security 관련 설정 임시 주석 처리 및 mysql 설정 추가
dnzp75 Mar 26, 2025
72d9f60
merge: feature/common-exception into feature/like-create
dnzp75 Mar 26, 2025
7ea9ed1
rename: BaseEntity 폴더 위치 수정
dnzp75 Mar 26, 2025
490b377
refactor: 예외처리 방식 각 Domain에 알맞게 수정
dnzp75 Mar 26, 2025
6163d80
refactor: 테스트 API 일부 제거
dnzp75 Mar 26, 2025
fe0f0f8
test: 좋아요 추가 API 테스트 코드 설명, 예외 처리 알맞게 수정
dnzp75 Mar 26, 2025
a97d94f
feat: 좋아요 취소 API 구현
dnzp75 Mar 26, 2025
e237e94
test: 좋아요 취소 API 단위 테스트 작성
dnzp75 Mar 26, 2025
ecf432b
remove: Test API 제거
dnzp75 Mar 26, 2025
3b92f9f
Merge pull request #7 from prgrms-web-devcourse-final-project/feature…
sapiens2000 Mar 27, 2025
e8620b2
test: PR GPT TST
dnzp75 Mar 27, 2025
612e2f5
chore: 브랜치명 변경 dev -> develop
sapiens2000 Mar 27, 2025
5081136
chore: develop 으로 pr 시 자코코 분석
sapiens2000 Mar 27, 2025
9133254
chore: sonarcloud branch 설정 변경
sapiens2000 Mar 27, 2025
fbbf50b
Merge pull request #9 from prgrms-web-devcourse-final-project/feature…
sapiens2000 Mar 27, 2025
f14f65a
Merge pull request #5 from prgrms-web-devcourse-final-project/feature…
dnzp75 Mar 27, 2025
2dbfe75
Merge branch 'develop' into feature/like-create
dnzp75 Mar 27, 2025
adb0836
Merge pull request #8 from prgrms-web-devcourse-final-project/feature…
dnzp75 Mar 27, 2025
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
148 changes: 148 additions & 0 deletions .github/scripts/code_review.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import os
import requests
import json
import re
from github import Github
from collections import defaultdict
from concurrent.futures import ThreadPoolExecutor, as_completed

def get_changed_files(pr):
changed_files = []
for file in pr.get_files():
if file.filename.endswith('.java'):
changed_files.append({
'filename': file.filename,
'patch': file.patch,
'status': file.status,
})
return changed_files

def get_file_content(repo, file_path, ref):
return repo.get_contents(file_path, ref=ref).decoded_content.decode('utf-8')

def search_file(repo, file, changed_files, ref):
if file.type == 'file' and file.name.endswith('.java'):
content = get_file_content(repo, file.path, ref)
related = set()
for changed_file in changed_files:
changed_name = os.path.splitext(os.path.basename(changed_file['filename']))[0]
if re.search(r'\b' + re.escape(changed_name) + r'\b', content):
related.add(changed_file['filename'])
return file.path, related
return None, set()

def find_related_files(repo, changed_files, ref):
related_files = defaultdict(set)
all_files = repo.get_contents('', ref=ref)
dirs_to_process = [file for file in all_files if file.type == 'dir']

with ThreadPoolExecutor(max_workers=10) as executor:
future_to_file = {executor.submit(search_file, repo, file, changed_files, ref): file for file in all_files if file.type == 'file'}

while dirs_to_process:
dir_files = repo.get_contents(dirs_to_process.pop().path, ref=ref)
dirs_to_process.extend([file for file in dir_files if file.type == 'dir'])
future_to_file.update({executor.submit(search_file, repo, file, changed_files, ref): file for file in dir_files if file.type == 'file'})

for future in as_completed(future_to_file):
file_path, related = future.result()
if related:
for changed_file in related:
related_files[changed_file].add(file_path)

return related_files


def call_claude_api(changes, related_files):
url = "https://api.anthropic.com/v1/messages"
headers = {
"Content-Type": "application/json",
"x-api-key": os.environ['CLAUDE_API_KEY'],
"anthropic-version": "2023-06-01"
}

system_content = (
"경험 많은 시니어 개발자로서, 다음 변경사항들에 대해 전체적이고 간결한 코드 리뷰를 수행해주세요.\n\n"
"리뷰 지침:\n"
"1. 모든 변경사항을 종합적으로 검토하고, 가장 중요한 문제점이나 개선사항에만 집중하세요.\n"
"2. 파일별로 개별 리뷰를 하지 말고, 전체 변경사항에 대한 통합된 리뷰를 제공하세요.\n"
"3. 각 주요 이슈에 대해 간단한 설명과 구체적인 개선 제안을 제시하세요.\n"
"4. 개선 제안에는 실제 코드 예시를 포함하세요. 단, 코드 예시는 제공한 코드와 연관된 코드여야 합니다. \n"
"5. 사소한 스타일 문제나 개인적 선호도는 무시하세요.\n"
"6. 심각한 버그, 성능 문제, 또는 보안 취약점이 있는 경우에만 언급하세요.\n"
"7. 전체 리뷰는 간결하게 유지하세요.\n"
"8. 변경된 부분만 집중하여 리뷰하고, 이미 개선된 코드를 다시 지적하지 마세요.\n"
"9. 기존에 이미 개선된 사항(예: 중복 코드 제거를 위한 함수 생성)을 인식하고 이를 긍정적으로 언급하세요.\n"
"10. 변경된 파일과 관련된 다른 파일들에 미칠 수 있는 영향을 분석하세요.\n\n"
"리뷰 형식:\n"
"- 개선된 사항: [이미 개선된 부분에 대한 긍정적 언급]\n"
"- 주요 이슈 (있는 경우에만):\n"
" 1. [문제 설명]\n"
" - 제안: [개선 방안 설명]\n"
" ```java\n"
" // 수정된 코드 예시\n"
" ```\n"
" 2. ...\n"
"- 관련 파일에 대한 영향 분석:\n"
" [변경된 파일과 관련된 다른 파일들에 미칠 수 있는 잠재적 영향 설명]\n"
"- 전반적인 의견: [1-2문장으로 요약]\n\n"
"변경된 파일들:\n"
)

for file_info in changes:
system_content += f"- {file_info['filename']} ({file_info['status']})\n"

system_content += "\n변경 내용:\n"
for file_info in changes:
system_content += f"파일: {file_info['filename']}\n전체 내용:\n{file_info['full_content']}\n\n변경된 부분:\n{file_info['patch']}\n\n"

system_content += "\n관련된 파일들:\n"
for changed_file, related in related_files.items():
system_content += f"- {changed_file}에 영향을 받을 수 있는 파일들:\n"
for related_file in related:
system_content += f" - {related_file}\n"

payload = {
"model": "claude-3-5-sonnet-20240620",
"max_tokens": 2000,
"system": system_content,
"messages": [
{
"role": "user",
"content": [
{
"type": "text",
"text": "제공된 모든 변경사항에 대해 통합된, 간결하고 핵심적인 코드 리뷰를 제공해주세요. 가장 중요한 이슈에만 집중하고, 각 개선 제안에는 구체적인 코드 예시를 포함해주세요. 변경된 부분만 집중하여 리뷰하고, 이미 개선된 코드를 다시 지적하지 마세요. 또한, 변경된 파일과 관련된 다른 파일들에 미칠 수 있는 잠재적 영향을 분석해주세요."
}
]
}
]
}

response = requests.post(url, headers=headers, json=payload)
if response.status_code == 200:
return response.json()['content'][0]['text']
else:
return f"Error: API returned status code {response.status_code}"

def main():
g = Github(os.environ['GITHUB_TOKEN'])
repo = g.get_repo(os.environ['GITHUB_REPOSITORY'])
pr_number = int(os.environ['PR_NUMBER'])
pr = repo.get_pull(pr_number)

changed_files = get_changed_files(pr)
changes = []

for file_info in changed_files:
full_content = get_file_content(repo, file_info['filename'], pr.head.sha)
file_info['full_content'] = full_content
changes.append(file_info)

related_files = find_related_files(repo, changed_files, pr.head.sha)
review = call_claude_api(changes, related_files)

pr.create_issue_comment(f"Claude의 전체 변경사항 및 관련 파일에 대한 리뷰:\n\n{review}")

if __name__ == "__main__":
main()
45 changes: 45 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: log4u-build
on:
# push:
# branches:
# - develop # dev 브랜치 push
pull_request:
branches:
- main # main pr
- develop # develop pr
types: [ opened, synchronize, reopened ]
jobs:
build:
name: Build and analyze
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: 21
distribution: 'zulu' # Alternative distribution options are available
- name: Cache Gradle packages
uses: actions/cache@v4
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
restore-keys: ${{ runner.os }}-gradle
- name: Cache SonarCloud packages
uses: actions/cache@v4
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar
- name: Build and analyze
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
DB_URL: ${{ secrets.DB_URL }} # Database URL
DB_USERNAME: ${{ secrets.DB_USERNAME }} # Database username
DB_PASSWORD: ${{ secrets.DB_PASSWORD }} # Database password
run: |
chmod +x ./gradlew
./gradlew build jacocoTestReport sonar --info -Dsonar.branch.name=${{ github.ref_name }}
34 changes: 34 additions & 0 deletions .github/workflows/code-review-claude.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Code Review from Claude

on:
pull_request:
types: [opened, synchronize]

permissions:
contents: read
pull-requests: write

jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0

- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.x'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install requests PyGithub
- name: Run Code Review
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CLAUDE_API_KEY: ${{ secrets.CLAUDE_API_KEY }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: python .github/scripts/code_review.py
20 changes: 20 additions & 0 deletions .github/workflows/code-review-gpt.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Code Review From ChatGPT

permissions:
contents: read
pull-requests: write

on:
pull_request:
types: [opened, synchronize]

jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: anc95/ChatGPT-CodeReview@main
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
LANGUAGE: Korean
MODEL: gpt-3.5-turbo
28 changes: 28 additions & 0 deletions .github/workflows/daily-archive.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Archive dev branch daily

on:
schedule:
- cron: "59 14 * * *" # 한국 시간(KST) 23:59 (UTC+14:59)
workflow_dispatch: # 수동 실행 가능

jobs:
archive:
name: Archive dev branch
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0 # 모든 브랜치 가져오기

- name: Set archive branch name
id: date
run: echo "BRANCH_NAME=archive-$(date +'%Y-%m-%d')" >> $GITHUB_ENV

- name: Create new archive branch
run: |
git checkout develop
git pull origin develop
git checkout -b ${{ env.BRANCH_NAME }}
git push origin ${{ env.BRANCH_NAME }}
34 changes: 32 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ plugins {
java
id("org.springframework.boot") version "3.4.4"
id("io.spring.dependency-management") version "1.1.7"
id("org.sonarqube") version "6.0.1.5171"
jacoco
checkstyle
}

group = "com.example"
Expand All @@ -25,13 +28,16 @@ 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-validation")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-data-redis")
implementation("mysql:mysql-connector-java:8.0.33")

compileOnly("org.projectlombok:lombok")
testCompileOnly("org.projectlombok:lombok")
testAnnotationProcessor("org.projectlombok:lombok")
runtimeOnly("com.h2database:h2")
annotationProcessor("org.projectlombok:lombok")
testImplementation("org.springframework.boot:spring-boot-starter-test")
Expand All @@ -50,3 +56,27 @@ dependencies {
tasks.withType<Test> {
useJUnitPlatform()
}

tasks.jacocoTestReport {
reports {
xml.required = true
csv.required = false
}
}

checkstyle {
configFile = file("${rootDir}/naver-checkstyle-rules.xml")
configProperties["suppressionFile"] = "${rootDir}/naver-checkstyle-suppressions.xml"
toolVersion = "9.2"
}

sonar {
properties {
property("sonar.projectKey", "sapiens2000-dev_simple-sns")
property("sonar.organization", "sapiens2000-dev")
property("sonar.host.url", "https://sonarcloud.io")
property("sonar.coverage.jacoco.xmlReportPaths", "build/reports/jacoco/test/jacocoTestReport.xml")
property("sonar.java.checkstyle.reportPaths", "build/reports/checkstyle/main.xml")
property("sonar.branch.name", System.getenv("BRANCH_NAME") ?: "main")
}
}
Loading