Skip to content

Commit 21bca1d

Browse files
committed
ci: workflow for checking unsolved user
1 parent 3b54883 commit 21bca1d

4 files changed

Lines changed: 324 additions & 7 deletions

File tree

.github/scripts/check_commits.py

Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
1+
#!/usr/bin/env python3
2+
"""
3+
매일 01:00에 실행되어 각 참여자의 커밋을 확인하고,
4+
- 어제 커밋이 없는 경우: 벌금 5000원
5+
- 어제 커밋이 없었는데 오늘 00:00~01:00 사이에 커밋한 경우: 지각 3000원
6+
Issue를 생성하고 README.md의 누적 적립금을 업데이트합니다.
7+
"""
8+
9+
import os
10+
import re
11+
from datetime import datetime, timezone, timedelta
12+
from github import Github
13+
from dateutil import parser
14+
15+
# GitHub 토큰
16+
GITHUB_TOKEN = os.environ.get('GITHUB_TOKEN')
17+
if not GITHUB_TOKEN:
18+
raise ValueError("GITHUB_TOKEN 환경변수가 설정되지 않았습니다.")
19+
20+
# 레포지토리 정보 (GitHub Actions 환경변수에서 자동으로 가져옴)
21+
GITHUB_REPOSITORY = os.environ.get('GITHUB_REPOSITORY', '')
22+
if GITHUB_REPOSITORY and '/' in GITHUB_REPOSITORY:
23+
REPO_OWNER, REPO_NAME = GITHUB_REPOSITORY.split('/', 1)
24+
else:
25+
REPO_OWNER = ''
26+
REPO_NAME = ''
27+
28+
# 참여자 정보 (이름: GitHub 사용자명)
29+
PARTICIPANTS = {
30+
'박예진': 'uiop5809',
31+
'김지호': 'jihostudy',
32+
'심수연': 'letthem',
33+
'정건우': 'abcxj123',
34+
'공예영': 'yeyounging'
35+
}
36+
37+
# 한국 시간대
38+
KST = timezone(timedelta(hours=9))
39+
40+
def get_today_kst():
41+
"""한국 시간 기준 오늘 날짜를 반환합니다."""
42+
return datetime.now(KST).date()
43+
44+
def check_user_commits(github, repo, username, start_time, end_time):
45+
"""특정 사용자가 특정 시간 범위에 커밋이 있는지 확인합니다."""
46+
try:
47+
# UTC로 변환
48+
start_time_utc = start_time.astimezone(timezone.utc)
49+
end_time_utc = end_time.astimezone(timezone.utc)
50+
51+
# 커밋 검색 (해당 시간 범위 내)
52+
commits = repo.get_commits(
53+
author=username,
54+
since=start_time_utc,
55+
until=end_time_utc
56+
)
57+
58+
# 커밋이 있는지 확인
59+
commit_count = sum(1 for _ in commits)
60+
return commit_count > 0
61+
62+
except Exception as e:
63+
print(f"사용자 {username}의 커밋 확인 중 오류 발생: {e}")
64+
return False
65+
66+
def create_issue(github, repo, participant_name, date_str, penalty_type, amount):
67+
"""미제출자 또는 지각자에 대한 Issue를 생성합니다."""
68+
if penalty_type == 'late':
69+
title = f"⏰ {date_str} 지각: {participant_name}"
70+
body = f"""
71+
## 지각 알림
72+
73+
**날짜**: {date_str}
74+
**참여자**: {participant_name}
75+
76+
{participant_name}님은 {date_str}에 커밋이 없었지만, 다음 날 00:00~01:00 사이에 커밋을 완료했습니다.
77+
78+
스터디 규칙에 따라 **3,000원**이 누적 적립금에 추가되었습니다.
79+
80+
---
81+
82+
*이 Issue는 자동으로 생성되었습니다.*
83+
"""
84+
labels = ['지각', '자동생성']
85+
else: # penalty_type == 'no_commit'
86+
title = f"⚠️ {date_str} 미제출: {participant_name}"
87+
body = f"""
88+
## 미제출 알림
89+
90+
**날짜**: {date_str}
91+
**참여자**: {participant_name}
92+
93+
{participant_name}님은 {date_str}에 커밋이 확인되지 않았습니다.
94+
95+
스터디 규칙에 따라 **5,000원**이 누적 적립금에 추가되었습니다.
96+
97+
---
98+
99+
*이 Issue는 자동으로 생성되었습니다.*
100+
"""
101+
labels = ['미제출', '자동생성']
102+
103+
try:
104+
issue = repo.create_issue(
105+
title=title,
106+
body=body,
107+
labels=labels
108+
)
109+
print(f"Issue 생성 완료: {issue.html_url}")
110+
return issue
111+
except Exception as e:
112+
print(f"Issue 생성 중 오류 발생: {e}")
113+
return None
114+
115+
def update_readme_penalty(participant_name, amount=5000):
116+
"""README.md의 누적 적립금을 업데이트합니다."""
117+
readme_path = 'README.md'
118+
119+
try:
120+
with open(readme_path, 'r', encoding='utf-8') as f:
121+
content = f.read()
122+
123+
# 누적 적립금 섹션 찾기
124+
pattern = rf'(\| {re.escape(participant_name)} \| )(\d+)원'
125+
126+
def replace_amount(match):
127+
current_amount = int(match.group(2))
128+
new_amount = current_amount + amount
129+
return f'{match.group(1)}{new_amount}원'
130+
131+
new_content = re.sub(pattern, replace_amount, content)
132+
133+
if new_content != content:
134+
with open(readme_path, 'w', encoding='utf-8') as f:
135+
f.write(new_content)
136+
print(f"README.md 업데이트 완료: {participant_name}님의 적립금 {amount}원 추가")
137+
return True
138+
else:
139+
print(f"README.md 업데이트 실패: {participant_name}님을 찾을 수 없습니다.")
140+
return False
141+
142+
except Exception as e:
143+
print(f"README.md 업데이트 중 오류 발생: {e}")
144+
return False
145+
146+
def main():
147+
"""메인 함수"""
148+
# GitHub API 초기화
149+
g = Github(GITHUB_TOKEN)
150+
151+
# 레포지토리 정보 확인
152+
if not REPO_OWNER or not REPO_NAME:
153+
print("레포지토리 정보를 찾을 수 없습니다. GITHUB_REPOSITORY 환경변수를 확인해주세요.")
154+
return
155+
156+
repo_owner = REPO_OWNER
157+
repo_name = REPO_NAME
158+
159+
try:
160+
repo = g.get_repo(f"{repo_owner}/{repo_name}")
161+
except Exception as e:
162+
print(f"레포지토리 접근 중 오류 발생: {e}")
163+
return
164+
165+
# 확인할 날짜 (어제 날짜, 한국 시간 기준)
166+
# 워크플로우가 01:00에 실행되므로 어제 날짜의 커밋을 확인
167+
today = get_today_kst()
168+
yesterday = today - timedelta(days=1)
169+
date_str = yesterday.strftime('%Y년 %m월 %d일')
170+
171+
print(f"=== {date_str} 커밋 확인 시작 ===")
172+
173+
# 주말 체크 (평일만 확인)
174+
weekday = yesterday.weekday() # 0=월요일, 6=일요일
175+
if weekday >= 5: # 토요일(5) 또는 일요일(6)
176+
print(f"{date_str}는 주말입니다. 스터디 규칙에 따라 확인을 건너뜁니다.")
177+
return
178+
179+
# 어제 날짜의 시간 범위 (00:00:00 ~ 23:59:59)
180+
yesterday_start = datetime.combine(yesterday, datetime.min.time()).replace(tzinfo=KST)
181+
yesterday_end = datetime.combine(today, datetime.min.time()).replace(tzinfo=KST) # 오늘 00:00:00
182+
183+
# 오늘 00:00~01:00 사이의 시간 범위 (지각 체크용)
184+
from datetime import time as dt_time
185+
today_start = datetime.combine(today, dt_time(0, 0, 0)).replace(tzinfo=KST) # 오늘 00:00:00
186+
today_01_00 = datetime.combine(today, dt_time(1, 0, 0)).replace(tzinfo=KST) # 오늘 01:00:00
187+
188+
no_commit_participants = [] # 어제 커밋이 없는 사람들
189+
late_participants = [] # 어제 커밋이 없었는데 오늘 00:00~01:00 사이에 커밋한 사람들
190+
191+
# 각 참여자의 커밋 확인
192+
for name, github_username in PARTICIPANTS.items():
193+
print(f"\n{name} (@{github_username}) 확인 중...")
194+
195+
# 어제 커밋 확인
196+
has_yesterday_commit = check_user_commits(g, repo, github_username, yesterday_start, yesterday_end)
197+
198+
if not has_yesterday_commit:
199+
print(f"❌ {name}님의 어제 커밋이 확인되지 않았습니다.")
200+
no_commit_participants.append(name)
201+
202+
# 오늘 00:00~01:00 사이에 커밋이 있는지 확인 (지각 체크)
203+
has_today_early_commit = check_user_commits(g, repo, github_username, today_start, today_01_00)
204+
205+
if has_today_early_commit:
206+
print(f"⏰ {name}님은 오늘 00:00~01:00 사이에 커밋을 완료했습니다. (지각)")
207+
late_participants.append(name)
208+
else:
209+
print(f"✅ {name}님의 어제 커밋이 확인되었습니다.")
210+
211+
# 처리할 참여자들
212+
penalty_participants = [] # 벌금 5000원 (어제 커밋 없음 + 오늘 00:00~01:00 사이에도 커밋 없음)
213+
214+
for participant in no_commit_participants:
215+
if participant not in late_participants:
216+
penalty_participants.append(participant)
217+
218+
# 벌금 처리 (어제 커밋 없음 = 5000원)
219+
if penalty_participants:
220+
print(f"\n=== 미제출자 {len(penalty_participants)}명 발견 (벌금 5000원) ===")
221+
222+
for participant_name in penalty_participants:
223+
# Issue 생성
224+
create_issue(g, repo, participant_name, date_str, 'no_commit', 5000)
225+
226+
# README.md 업데이트
227+
update_readme_penalty(participant_name, 5000)
228+
229+
# 지각 처리 (어제 커밋 없음 + 오늘 00:00~01:00 사이 커밋 있음 = 3000원)
230+
if late_participants:
231+
print(f"\n=== 지각자 {len(late_participants)}명 발견 (지각 3000원) ===")
232+
233+
for participant_name in late_participants:
234+
# Issue 생성
235+
create_issue(g, repo, participant_name, date_str, 'late', 3000)
236+
237+
# README.md 업데이트
238+
update_readme_penalty(participant_name, 3000)
239+
240+
# 변경사항 커밋
241+
if penalty_participants or late_participants:
242+
try:
243+
import subprocess
244+
subprocess.run(['git', 'config', 'user.name', 'github-actions[bot]'], check=True)
245+
subprocess.run(['git', 'config', 'user.email', 'github-actions[bot]@users.noreply.github.com'], check=True)
246+
subprocess.run(['git', 'add', 'README.md'], check=True)
247+
248+
commit_message = f'[자동] {date_str} 누적 적립금 업데이트'
249+
if penalty_participants:
250+
commit_message += f' (미제출: {", ".join(penalty_participants)})'
251+
if late_participants:
252+
commit_message += f' (지각: {", ".join(late_participants)})'
253+
254+
subprocess.run(['git', 'commit', '-m', commit_message], check=True)
255+
subprocess.run(['git', 'push'], check=True)
256+
print("\n✅ README.md 변경사항이 커밋되었습니다.")
257+
except Exception as e:
258+
print(f"\n⚠️ README.md 커밋 중 오류 발생: {e}")
259+
else:
260+
print("\n✅ 모든 참여자가 커밋을 완료했습니다!")
261+
262+
print(f"\n=== {date_str} 커밋 확인 완료 ===")
263+
264+
if __name__ == '__main__':
265+
main()
266+
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: Check Daily Commits
2+
3+
on:
4+
schedule:
5+
# 매일 01:00 (UTC 기준, 한국시간 오전 10시)
6+
# 한국시간 01:00으로 하려면: cron: '0 16 * * *' (UTC 16시 = 한국시간 01:00)
7+
- cron: "0 16 * * *"
8+
workflow_dispatch: # 수동 실행도 가능하도록
9+
10+
permissions:
11+
contents: write # README.md 업데이트를 위한 권한
12+
issues: write # Issue 생성을 위한 권한
13+
14+
jobs:
15+
check-commits:
16+
runs-on: ubuntu-latest
17+
18+
steps:
19+
- name: Checkout repository
20+
uses: actions/checkout@v4
21+
with:
22+
token: ${{ secrets.GITHUB_TOKEN }}
23+
fetch-depth: 0 # 전체 커밋 히스토리 가져오기
24+
25+
- name: Set up Python
26+
uses: actions/setup-python@v5
27+
with:
28+
python-version: "3.11"
29+
30+
- name: Install dependencies
31+
run: |
32+
pip install PyGithub python-dateutil
33+
34+
- name: Check commits and update README
35+
env:
36+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
37+
run: |
38+
python .github/scripts/check_commits.py

.vscode/settings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"folder-color.pathColors": []
3+
}

README.md

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,23 @@ algorithm/
5252

5353
## 참여자
5454

55-
| 이름 | GitHub |
56-
| ------ | ------------------------------------------ |
57-
| 박예진 | [@uiop5809](https://github.com/uiop5809) |
58-
| 김지호 | [@jihostudy](https://github.com/jihostudy) |
59-
| 심수연 | [@letthem](https://github.com/letthem) |
60-
| 정건우 | [@abcxj123](https://github.com/abcxj123) |
61-
| 공예영 | [@yeyounging](https://github.com/yeyounging)|
55+
| 이름 | GitHub |
56+
| ------ | -------------------------------------------- |
57+
| 박예진 | [@uiop5809](https://github.com/uiop5809) |
58+
| 김지호 | [@jihostudy](https://github.com/jihostudy) |
59+
| 심수연 | [@letthem](https://github.com/letthem) |
60+
| 정건우 | [@abcxj123](https://github.com/abcxj123) |
61+
| 공예영 | [@yeyounging](https://github.com/yeyounging) |
62+
63+
## 회식비 제공 천사 🪽
64+
65+
| 이름 | 누적 |
66+
| ------ | ---- |
67+
| 박예진 | 0원 |
68+
| 김지호 | 0원 |
69+
| 심수연 | 0원 |
70+
| 정건우 | 0원 |
71+
| 공예영 | 0원 |
6272

6373
---
6474

0 commit comments

Comments
 (0)