Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
pp449 committed Oct 19, 2024
2 parents ffdb560 + 5f5466f commit 5d937e6
Show file tree
Hide file tree
Showing 228 changed files with 4,976 additions and 1,618 deletions.
189 changes: 189 additions & 0 deletions .github/scripts/pr-stats.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
import csv
import json
import requests
import os
from datetime import datetime, timedelta, timezone

# 한국 표준시 타임존 설정
KST = timezone(timedelta(hours=9))

# Slack Webhook URL 설정 (GitHub Secrets에서 불러옴)
slack_webhook_url = os.getenv("SLACK_WEBHOOK_URL")
pr_html_url = os.getenv("PR_HTML_URL")
assignee = os.getenv("ASSIGNEE")
pr_number = os.getenv("PR_NUMBER")

users = {
"youngsu5582" : "조휘선",
"hjk0761" : "무빈",
"ashsty" : "애쉬",
"jcoding-play" : "뽀로로",
"pp449" : "다르",
"00kang" : "초코",
"chlwlstlf" : "텐텐"
}

def construct_message(title,created_at,merged_at,difference,file_count,line_count,conversation_count,response_time,approval_time):
name = users.get(assignee,"누군가")
slack_message= {
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": f"<{pr_html_url}|{title}> 이 머지되었습니다. 😎 ( 수고했어요 {name} )"
}
},
{
"type": "divider"
},
{
"type": "rich_text",
"elements": [
{
"type": "rich_text_section",
"elements": [
{
"type": "text",
"text": " PR 정보 "
}
]
},
{
"type": "rich_text_list",
"style": "bullet",
"elements": [
{
"type": "rich_text_section",
"elements": [
{
"type": "text",
"text": f"PR 기간 : {created_at} ~ {merged_at} ( 소요 시간 : {difference} ✅ )"
}
]
},
{
"type": "rich_text_section",
"elements": [
{
"type": "text",
"text": f"변경 된 파일 수 : {file_count} ( 라인 수 : {line_count} )"
}
]
},
{
"type": "rich_text_section",
"elements": [
{
"type": "text",
"text": f"대화 수 : {conversation_count} "
},
{
"type": "emoji",
"name": "thumbsup"
}
]
},
{
"type": "rich_text_section",
"elements": [
{
"type": "text",
"text": f"평균 응답 시간 : {response_time}"
}
]
},
{
"type": "rich_text_section",
"elements": [
{
"type": "text",
"text": f"평균 승인 시간 : {approval_time}"
}
]
}
]
}
]
}
]
}
print(slack_message)
return slack_message


# Slack Webhook 메시지 전송 함수
def send_slack_message_via_webhook(message):
headers = {
'Content-Type': 'application/json',
}
response = requests.post(slack_webhook_url, headers=headers, data=json.dumps(message))

if response.status_code != 200:
raise ValueError(f"Request to Slack returned an error {response.status_code}, the response is:\n{response.text}")

# 타임스탬프를 한국 시간으로 변환하는 함수
def convert_timestamp_to_kst(timestamp_ms):
timestamp_sec = int(timestamp_ms) / 1000
dt = datetime.fromtimestamp(timestamp_sec, tz=timezone.utc).astimezone(KST)
return dt.strftime("%m월%d일 %H시 %M분")

# 밀리초 시간을 사람이 읽을 수 있는 형식으로 변환하는 함수
def format_duration(ms):
if ms == 'NaN':
return "N/A"

total_seconds = int(round(float(ms))) / 1000
days, remainder = divmod(total_seconds, 86400) # 86400초 = 1일
hours, remainder = divmod(remainder, 3600) # 3600초 = 1시간
minutes, _ = divmod(remainder, 60)

if days > 0:
return f"{int(days)}{int(hours)}시간 {int(minutes)}분 😢"
else:
return f"{int(hours)}시간 {int(minutes)}분 🙂"

# CSV 파일 분석 함수
def analyze_csv(file_path):
with open(file_path, newline='') as csvfile:
reader = csv.DictReader(csvfile)
stats = []
for row in reader:
stats.append(row)
return stats

# 주요 통계 정보 추출
def extract_important_info(pr_data):
return next((pr for pr in pr_data if pr['number'] == pr_number), None)

# 통계 분석 및 보고서 작성
def generate_report(pr_stats):
pr = extract_important_info(pr_stats)

if pr is None:
print("No PR found with the specified PR number. Exiting...")
return

print(pr)
created_at_timestamp = pr['createdAt']
merged_at_timestamp = pr['mergedAt']
# 정보 추출
created_at = convert_timestamp_to_kst(created_at_timestamp)
merged_at = convert_timestamp_to_kst(merged_at_timestamp)
difference = format_duration(int(merged_at_timestamp)-int(created_at_timestamp))
title = pr['title']
file_count = pr['fileCount']
changed_line_count = pr['changedLineCount']
conversation_count = pr['conversationCount']

# 시간 포맷팅
response_time = format_duration(pr['averageResponseTime'])
approval_time = format_duration(pr['averageTimeToApproval'])

message = construct_message(title,created_at,merged_at,difference,file_count,changed_line_count,conversation_count,response_time,approval_time)

send_slack_message_via_webhook(message)

# 실행
pr_stats = analyze_csv('./stats/pr.csv')
generate_report(pr_stats)
41 changes: 41 additions & 0 deletions .github/workflows/pr-stats.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# .github/workflows/pr-stats.yml
name: PR Stats and Notifications

on:
pull_request:
types:
- closed # PR이 닫힐 때 트리거

jobs:
pr-stats-job:
if: github.event.pull_request.merged == true # PR이 merge된 경우에만 실행
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.x' # Python 3.x 버전 사용

- name: Install Python dependencies
run: |
python -m pip install --upgrade pip
pip install slack_sdk requests
- name: Run PR Stats
uses: "naver/[email protected]"
with:
token: ${{ secrets.GITHUB_TOKEN }}
count: 15

- name: Analyze PR Stats and Notify
run: |
python .github/scripts/pr-stats.py
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
PR_HTML_URL: ${{ github.event.pull_request.html_url }}
ASSIGNEE: ${{ github.event.pull_request.assignee.login }}
PR_NUMBER: ${{ github.event.pull_request.number }}
415 changes: 312 additions & 103 deletions backend/src/main/java/corea/ContextInitializer.java

Large diffs are not rendered by default.

31 changes: 16 additions & 15 deletions backend/src/main/java/corea/DataInitializer.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package corea;

import corea.member.domain.Member;
import corea.member.domain.MemberRole;
import corea.member.repository.MemberRepository;
import corea.participation.domain.Participation;
import corea.participation.repository.ParticipationRepository;
Expand Down Expand Up @@ -182,27 +183,27 @@ public void run(ApplicationArguments args) {
LocalDateTime.of(2024, 12, 30, 12, 20),
RoomClassification.ANDROID, RoomStatus.PROGRESS));

participationRepository.save(new Participation(room1, member2.getId()));
participationRepository.save(new Participation(room1, member3.getId()));
participationRepository.save(new Participation(room1, member2, MemberRole.BOTH, room1.getMatchingSize()));
participationRepository.save(new Participation(room1, member3, MemberRole.BOTH, room1.getMatchingSize()));

participationRepository.save(new Participation(room2, member3.getId()));
participationRepository.save(new Participation(room2, member4.getId()));
participationRepository.save(new Participation(room2, member3, MemberRole.BOTH, room2.getMatchingSize()));
participationRepository.save(new Participation(room2, member4, MemberRole.BOTH, room2.getMatchingSize()));

participationRepository.save(new Participation(room3, member4.getId()));
participationRepository.save(new Participation(room3, member5.getId()));
participationRepository.save(new Participation(room3, member4, MemberRole.BOTH, room3.getMatchingSize()));
participationRepository.save(new Participation(room3, member5, MemberRole.BOTH, room3.getMatchingSize()));

participationRepository.save(new Participation(room4, member5.getId()));
participationRepository.save(new Participation(room4, member6.getId()));
participationRepository.save(new Participation(room4, member5, MemberRole.BOTH, room4.getMatchingSize()));
participationRepository.save(new Participation(room4, member6, MemberRole.BOTH, room4.getMatchingSize()));

participationRepository.save(new Participation(room5, member6.getId()));
participationRepository.save(new Participation(room5, member7.getId()));
participationRepository.save(new Participation(room5, member6, MemberRole.BOTH, room5.getMatchingSize()));
participationRepository.save(new Participation(room5, member7, MemberRole.BOTH, room5.getMatchingSize()));

participationRepository.save(new Participation(room6, member1.getId()));
participationRepository.save(new Participation(room6, member7.getId()));
participationRepository.save(new Participation(room6, member1, MemberRole.BOTH, room6.getMatchingSize()));
participationRepository.save(new Participation(room6, member7, MemberRole.BOTH, room6.getMatchingSize()));

participationRepository.save(new Participation(room7, member1.getId()));
participationRepository.save(new Participation(room7, member2.getId()));
participationRepository.save(new Participation(room7, member1, MemberRole.BOTH, room7.getMatchingSize()));
participationRepository.save(new Participation(room7, member2, MemberRole.BOTH, room7.getMatchingSize()));

participationRepository.save(new Participation(roomProgress, member1.getId()));
participationRepository.save(new Participation(roomProgress, member1, MemberRole.BOTH, roomProgress.getMatchingSize()));
}
}
3 changes: 2 additions & 1 deletion backend/src/main/java/corea/auth/domain/LoginInfo.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package corea.auth.domain;

import corea.global.BaseTimeEntity;
import corea.member.domain.Member;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
Expand All @@ -13,7 +14,7 @@
@AllArgsConstructor
@NoArgsConstructor(access = PROTECTED)
@Getter
public class LoginInfo {
public class LoginInfo extends BaseTimeEntity {

@Id
@GeneratedValue(strategy = IDENTITY)
Expand Down
2 changes: 1 addition & 1 deletion backend/src/main/java/corea/auth/domain/TokenInfo.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package corea.auth.domain;

public record TokenInfo (String accessToken, String refreshToken){
public record TokenInfo(String accessToken, String refreshToken) {
}
16 changes: 16 additions & 0 deletions backend/src/main/java/corea/auth/dto/GithubPullRequestReview.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package corea.auth.dto;

import com.fasterxml.jackson.annotation.JsonProperty;

public record GithubPullRequestReview(

@JsonProperty("id")
String id,

@JsonProperty("user")
GithubUserInfo user,

@JsonProperty("html_url")
String html_url
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import corea.auth.dto.GithubAuthRequest;
import corea.auth.dto.GithubAuthResponse;
import corea.auth.dto.GithubPullRequestReview;
import corea.auth.dto.GithubUserInfo;
import corea.exception.CoreaException;
import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -58,4 +59,13 @@ public GithubUserInfo getUserInfo(String accessToken) {
.retrieve()
.body(GithubUserInfo.class);
}

public GithubPullRequestReview[] getReviewLink(String prLink) {
String url = GithubPullRequestUrlExchanger.pullRequestUrlToReview(prLink);
return restClient.get()
.uri(url)
.accept(APPLICATION_JSON)
.retrieve()
.body(GithubPullRequestReview[].class);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import java.util.List;

@ConfigurationProperties(prefix = "security.github")
public record GithubProperties(BaseUrl baseUrl, OAuth oauth,PullRequest pullRequest) {
public record GithubProperties(BaseUrl baseUrl, OAuth oauth, PullRequest pullRequest) {

public record BaseUrl(String oauth, String user) {
}
Expand Down
Loading

0 comments on commit 5d937e6

Please sign in to comment.