Skip to content

Commit 20f517e

Browse files
authored
Merge pull request #165 from AlgorithmStudy-Allumbus/minjeong
Feat: ์ฑŒ๋ฆฐ์ง€ ์ง„ํ–‰ ๊ด€๋ฆฌ ์ž๋™ํ™”
2 parents 183ef27 + b7593c7 commit 20f517e

File tree

6 files changed

+321
-0
lines changed

6 files changed

+321
-0
lines changed
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
name: Update Challenge Progress
2+
3+
on:
4+
pull_request:
5+
types: [opened, edited, reopened]
6+
7+
jobs:
8+
update_progress:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- name: Checkout Repository
12+
uses: actions/checkout@v3
13+
with:
14+
ref: ${{ github.head_ref }}
15+
fetch-depth: 0
16+
17+
- name: Set up Python
18+
uses: actions/setup-python@v4
19+
with:
20+
python-version: '3.x'
21+
22+
- name: Run extract_pr_data.py
23+
working-directory: _MonthlyChallenges
24+
run: python extract_pr_data.py
25+
26+
- name: Run update_scoreboard.py
27+
working-directory: _MonthlyChallenges
28+
run: python update_scoreboard.py
29+
30+
- name: Run update_dashboard.py
31+
working-directory: _MonthlyChallenges
32+
run: python update_dashboard.py
33+
34+
- name: Commit updated files
35+
working-directory: _MonthlyChallenges
36+
run: |
37+
git config --global user.name "${{ secrets.GIT_USER_NAME }}"
38+
git config --global user.email "${{ secrets.GIT_USER_EMAIL }}"
39+
git add scoreboard.json DASHBOARD.md HISTORY.md
40+
git commit -m "Update challenge progress dashboard" || echo "No changes to commit"
41+
git push origin ${{ github.head_ref }}
42+
43+
- name: Post PR Comment with progress
44+
if: github.event_name == 'pull_request'
45+
uses: actions/github-script@v6
46+
with:
47+
script: |
48+
const fs = require('fs');
49+
// DASHBOARD.md ํŒŒ์ผ์—์„œ ๋‚ด์šฉ ์ฝ์–ด์˜ค๊ธฐ (working-directory์— ๋”ฐ๋ผ ๊ฒฝ๋กœ ์กฐ์ •)
50+
const dashboard = fs.readFileSync('_MonthlyChallenges/DASHBOARD.md', 'utf8');
51+
// PR ์ด๋ฒคํŠธ์—์„œ PR ๋ฒˆํ˜ธ ๊ฐ€์ ธ์˜ค๊ธฐ
52+
const prNumber = context.payload.pull_request.number;
53+
// GitHub REST API๋ฅผ ํ†ตํ•ด ์ฝ”๋ฉ˜ํŠธ ์ƒ์„ฑ
54+
github.rest.issues.createComment({
55+
owner: context.repo.owner,
56+
repo: context.repo.repo,
57+
issue_number: prNumber,
58+
body: dashboard
59+
});

โ€Ž_MonthlyChallenges/DASHBOARD.mdโ€Ž

Whitespace-only changes.

โ€Ž_MonthlyChallenges/HISTORY.mdโ€Ž

Whitespace-only changes.
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import os
2+
import json
3+
import re
4+
5+
6+
def main():
7+
# 1. GitHub ์ด๋ฒคํŠธ ํŽ˜์ด๋กœ๋“œ ๋กœ๋“œ
8+
event_path = os.getenv('GITHUB_EVENT_PATH')
9+
print("event_path", event_path)
10+
if not event_path:
11+
print("GITHUB_EVENT_PATH ํ™˜๊ฒฝ๋ณ€์ˆ˜๊ฐ€ ์„ค์ •๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.")
12+
exit(1)
13+
14+
with open(event_path, 'r', encoding='utf-8') as f:
15+
event_data = json.load(f)
16+
print(f"event_data: {event_data}")
17+
18+
pr_body = event_data['pull_request']['body']
19+
pr_number = event_data['pull_request']['number']
20+
username = event_data['pull_request']['user']['login']
21+
print(f"pr_body: {pr_body}, pr_number: {pr_number}")
22+
23+
if pr_number is None:
24+
print("PR ๋ฒˆํ˜ธ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")
25+
exit(1)
26+
27+
# 2. PR ๋ณธ๋ฌธ์„ ์ค„ ๋‹จ์œ„๋กœ ๋ถ„ํ• 
28+
lines = pr_body.splitlines()
29+
print(f"lines: {lines}")
30+
31+
# 3. "ํ‘ผ ๋ฌธ์ œ" ์„น์…˜ ํƒ์ง€ ๋ฐ ๋ฌธ์ œ ํ•ญ๋ชฉ ํŒŒ์‹ฑ
32+
in_problem_section = False
33+
problem_entries = []
34+
35+
# ์ •๊ทœํ‘œํ˜„์‹ ํŒจํ„ด:
36+
# - [๋ฐฑ์ค€ #2169. ๋กœ๋ด‡ ์กฐ์ข…ํ•˜๊ธฐ](https://www.acmicpc.net/problem/2169): DP / ๊ณจ๋“œ2
37+
pattern = r'- \[(?P<source>[^\]]+?) #(?P<id>\d+)\.\s+(?P<title>.*?)\]\((?P<link>.*?)\):\s*(?P<algorithm>[^/]+)\s*/\s*(?P<difficulty>.+)'
38+
39+
for line in lines:
40+
# "ํ‘ผ ๋ฌธ์ œ" ํ‚ค์›Œ๋“œ๋ฅผ ์ฐพ์œผ๋ฉด ํ•ด๋‹น ์„น์…˜ ์‹œ์ž‘์œผ๋กœ ์„ค์ •
41+
if "ํ‘ผ ๋ฌธ์ œ" in line:
42+
in_problem_section = True
43+
continue
44+
45+
if in_problem_section:
46+
# bullet list ํ•ญ๋ชฉ๋งŒ ์ฒ˜๋ฆฌ
47+
if line.startswith('- '):
48+
match = re.match(pattern, line)
49+
print(f"match: {match}")
50+
if match:
51+
entry = match.groupdict()
52+
print(f"entry: {entry}")
53+
# ๋ฌธ์ œ ๋ฒˆํ˜ธ๋ฅผ ์ •์ˆ˜๋กœ ๋ณ€ํ™˜
54+
entry['problem_id'] = int(entry.pop("id"))
55+
entry['pr_number'] = pr_number
56+
entry['username'] = username
57+
# ๊ณต๋ฐฑ ์ œ๊ฑฐ
58+
entry['algorithm'] = entry['algorithm'].strip()
59+
entry['difficulty'] = entry['difficulty'].strip()
60+
problem_entries.append(entry)
61+
print(f"problem_entries: {problem_entries}")
62+
63+
# 4. ์ถ”์ถœ๋œ ๋ฐ์ดํ„ฐ๋ฅผ pr_data.json ํŒŒ์ผ์— ์ €์žฅ
64+
with open("pr_data.json","w", encoding='utf-8') as f:
65+
json.dump(problem_entries, f, ensure_ascii=False, indent=2)
66+
67+
if __name__ == '__main__':
68+
main()
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import os
2+
import json
3+
from datetime import datetime
4+
5+
SCOREBOARD_FILE = "scoreboard.json"
6+
DASHBOARD_FILE = "DASHBOARD.md"
7+
HISTORY_FILE = "HISTORY.md"
8+
9+
CHALLENGE_TYPES = {
10+
"๊ทธ๋ž˜ํ”„": 5,
11+
"DP": 5
12+
}
13+
14+
def generate_dashboard(scoreboard):
15+
# scoreboard ๊ตฌ์กฐ ์˜ˆ์‹œ (์ƒˆ๋กœ์šด ํ˜•์‹):
16+
# {
17+
# "month": "2023-04",
18+
# "users": {
19+
# "user1": {
20+
# "๊ทธ๋ž˜ํ”„": [101, 102],
21+
# "DP": [2169, 1520],
22+
# "achieved": {
23+
# "๊ทธ๋ž˜ํ”„": true,
24+
# "DP": false
25+
# }
26+
# },
27+
# "user2": { ... }
28+
# }
29+
# }
30+
month = scoreboard.get("month", "Unknown")
31+
users = scoreboard.get("users", {})
32+
33+
md = f"# {month} ์ฑŒ๋ฆฐ์ง€ ์ง„ํ–‰ ์ƒํ™ฉ\n\n"
34+
md += "| ์‚ฌ์šฉ์ž | ์ฑŒ๋ฆฐ์ง€ ์œ ํ˜• | ๋ฌธ์ œ ์ˆ˜ | ๋‹ฌ์„ฑ ์—ฌ๋ถ€ |\n"
35+
md += "| ------ | ----------- | ------- | --------- |\n"
36+
37+
# ๊ฐ ์‚ฌ์šฉ์ž๋ณ„ ์ง„ํ–‰ ์ƒํ™ฉ ํ‘œ ์ž‘์„ฑ
38+
for user, data in users.items():
39+
for ctype in CHALLENGE_TYPES.keys():
40+
count = len(data.get(ctype, []))
41+
achieved = data.get("achieved", {}).get(ctype, False)
42+
achieved_str = "โœ…" if achieved else "โŒ"
43+
md += f"| {user} | {ctype} | {count} | {achieved_str} |\n"
44+
45+
return md
46+
47+
def archive_current_month(scoreboard):
48+
# HISTORY_FILE์— ํ˜„์žฌ ๋‹ฌ ๊ธฐ๋ก์„ ์ถ”๊ฐ€ (append ๋ฐฉ์‹)
49+
dashboard_md = generate_dashboard(scoreboard)
50+
with open(HISTORY_FILE, "a", encoding="utf-8") as f:
51+
f.write(dashboard_md)
52+
f.write("\n\n") # ๊ตฌ๋ถ„์„ ์œ„ํ•œ ๋นˆ ์ค„ ์ถ”๊ฐ€
53+
print("HISTORY.md ์—…๋ฐ์ดํŠธ ์™„๋ฃŒ!")
54+
55+
def update_dashboard():
56+
# 1. scoreboard.json ๋กœ๋“œ
57+
if not os.path.exists(SCOREBOARD_FILE):
58+
print(f"{SCOREBOARD_FILE} ํŒŒ์ผ์ด ์—†์Šต๋‹ˆ๋‹ค.")
59+
return
60+
61+
with open(SCOREBOARD_FILE, "r", encoding="utf-8") as f:
62+
scoreboard = json.load(f)
63+
64+
# 2. ๊ธฐ์กด ํŒŒ์ผ ๊ตฌ์กฐ๊ฐ€ ์ƒˆ ํ˜•์‹("month", "users")์ด ์•„๋‹ˆ๋ผ๋ฉด ๋ณ€ํ™˜
65+
if "month" not in scoreboard or "users" not in scoreboard:
66+
# ๊ธฐ์กด ๊ตฌ์กฐ๋Š” ์‚ฌ์šฉ์ž ์ด๋ฆ„์ด ์ตœ์ƒ์œ„ ํ‚ค์ธ ํ˜•ํƒœ
67+
scoreboard = {
68+
"month": datetime.now().strftime("%Y-%m"),
69+
"users": scoreboard
70+
}
71+
# ์ƒˆ ํ˜•์‹์œผ๋กœ ์ €์žฅ
72+
with open(SCOREBOARD_FILE, "w", encoding="utf-8") as f:
73+
json.dump(scoreboard, f, ensure_ascii=False, indent=2)
74+
print("๊ธฐ์กด scoreboard ํ˜•์‹์„ ์ƒˆ ๊ตฌ์กฐ๋กœ ๋ณ€ํ™˜ํ•˜์˜€์Šต๋‹ˆ๋‹ค.")
75+
76+
# 3. ํ˜„์žฌ ๋‹ฌ ํ™•์ธ ๋ฐ ์›” ์ดˆ๊ธฐํ™” ์ฒ˜๋ฆฌ
77+
current_month = datetime.now().strftime("%Y-%m")
78+
stored_month = scoreboard.get("month", current_month)
79+
print(f"ํ˜„์žฌ ๋‹ฌ: {current_month}, ์ €์žฅ๋œ ๋‹ฌ: {stored_month}")
80+
81+
if stored_month != current_month:
82+
print(f"์ƒˆ๋กœ์šด ๋‹ฌ({current_month})๋กœ ๋„˜์–ด๊ฐ - ์ด์ „ ๋‹ฌ({stored_month}) ๊ธฐ๋ก์„ ํžˆ์Šคํ† ๋ฆฌ์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.")
83+
archive_current_month(scoreboard)
84+
# scoreboard ์ดˆ๊ธฐํ™”: users๋Š” ๋นˆ dict, month๋Š” ํ˜„์žฌ ๋‹ฌ๋กœ ๊ฐฑ์‹ 
85+
scoreboard = {
86+
"month": current_month,
87+
"users": {}
88+
}
89+
with open(SCOREBOARD_FILE, "w", encoding="utf-8") as f:
90+
json.dump(scoreboard, f, ensure_ascii=False, indent=2)
91+
92+
# 4. DASHBOARD.md ํŒŒ์ผ ์ƒ์„ฑ ๋ฐ ์—…๋ฐ์ดํŠธ
93+
md_content = generate_dashboard(scoreboard)
94+
with open(DASHBOARD_FILE, "w", encoding="utf-8") as f:
95+
f.write(md_content)
96+
97+
print("DASHBOARD.md ์—…๋ฐ์ดํŠธ ์™„๋ฃŒ!")
98+
99+
if __name__ == '__main__':
100+
update_dashboard()
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import os
2+
import json
3+
from datetime import datetime
4+
5+
SCOREBOARD_FILE = "scoreboard.json"
6+
PR_DATA_FILE = "pr_data.json"
7+
8+
# ์ฑŒ๋ฆฐ์ง€ ์„ค์ • (๋งค๋‹ฌ ํˆฌํ‘œ ๊ฒฐ๊ณผ๋กœ ์ •ํ•ด์ง„ ์œ ํ˜•๊ณผ ๋ชฉํ‘œ ๋ฌธ์ œ ์ˆ˜)
9+
CHALLENGE_TYPES = {
10+
"๊ทธ๋ž˜ํ”„": 5,
11+
"DP": 5
12+
}
13+
14+
15+
def initialize_user():
16+
# ์‚ฌ์šฉ์ž๋ณ„ ์ดˆ๊ธฐ ์Šค์ฝ”์–ด๋ณด๋“œ ๊ตฌ์กฐ
17+
return {
18+
**{ctype: [] for ctype in CHALLENGE_TYPES.keys()},
19+
"achieved": {ctype: False for ctype in CHALLENGE_TYPES.keys()}
20+
}
21+
22+
23+
def main():
24+
# 1. ๊ธฐ์กด ์Šค์ฝ”์–ด๋ณด๋“œ ๋กœ๋“œ (์—†์œผ๋ฉด ๋นˆ dict๋กœ ์ดˆ๊ธฐํ™”)
25+
if os.path.exists(SCOREBOARD_FILE):
26+
with open(SCOREBOARD_FILE, 'r', encoding='utf-8') as f:
27+
try:
28+
scoreboard = json.load(f)
29+
except json.JSONDecodeError:
30+
scoreboard = {}
31+
else:
32+
scoreboard = {}
33+
34+
print(f"scorebard: {scoreboard}")
35+
36+
# 2. ์ƒˆ ๊ตฌ์กฐ("month", "users")๊ฐ€ ์—†๋‹ค๋ฉด ๋ณ€ํ™˜
37+
if "users" not in scoreboard or "month" not in scoreboard:
38+
scoreboard = {
39+
"month": datetime.now().strftime("%Y-%m"),
40+
"users": scoreboard # ๊ธฐ์กด scoreboard์˜ ๋‚ด์šฉ(์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ)์ด ์žˆ๋‹ค๋ฉด ์—ฌ๊ธฐ์— ๋„ฃ์Œ
41+
}
42+
43+
users = scoreboard["users"]
44+
45+
# 3. pr_data.json ํŒŒ์ผ ๋กœ๋“œ
46+
if not os.path.exists(PR_DATA_FILE):
47+
print(f"{PR_DATA_FILE} ํŒŒ์ผ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.")
48+
exit(1)
49+
50+
with open(PR_DATA_FILE, 'r', encoding='utf-8') as f:
51+
pr_data = json.load(f)
52+
53+
print(f"pr_data: {pr_data}")
54+
55+
# 4. pr_data์˜ ๊ฐ ํ•ญ๋ชฉ์„ ์ˆœํšŒํ•˜๋ฉฐ ์‚ฌ์šฉ์ž๋ณ„ ์Šค์ฝ”์–ด๋ณด๋“œ ์—…๋ฐ์ดํŠธ
56+
for entry in pr_data:
57+
username = entry["username"]
58+
algorithm = entry["algorithm"]
59+
problem_id = entry["problem_id"]
60+
61+
if not username or not algorithm or problem_id is None:
62+
continue
63+
64+
print(f"username: {username}, algorithm: {algorithm}, problem_id: {problem_id}")
65+
66+
# ์ฑŒ๋ฆฐ์ง€ ์œ ํ˜•์— ํฌํ•จ๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธ (์˜ˆ: "๊ทธ๋ž˜ํ”„", "DP")
67+
if algorithm not in CHALLENGE_TYPES:
68+
continue # ์ฑŒ๋ฆฐ์ง€ ๋Œ€์ƒ์ด ์•„๋‹ˆ๋ฉด ๋ฌด์‹œ
69+
70+
# ์‚ฌ์šฉ์ž์˜ ๊ธฐ๋ก์ด ์—†์œผ๋ฉด ์ดˆ๊ธฐํ™”
71+
if username not in users:
72+
scoreboard[username] = initialize_user()
73+
74+
# ํ•ด๋‹น ์œ ํ˜• ๋ฌธ์ œ ๋ฒˆํ˜ธ๋ฅผ ์ค‘๋ณต ์—†์ด ์ถ”๊ฐ€
75+
if problem_id not in users[username].get(algorithm, []):
76+
users[username][algorithm].append(problem_id)
77+
78+
print(f"users: {users}")
79+
80+
# 5. ๊ฐ ์‚ฌ์šฉ์ž๋ณ„๋กœ ๋‹ฌ์„ฑ ์—ฌ๋ถ€ ์—…๋ฐ์ดํŠธ
81+
for username, data in users.items():
82+
for ctype, goal in CHALLENGE_TYPES.items():
83+
count = len(data.get(ctype, []))
84+
# ๋ชฉํ‘œ ์ˆ˜ ์ด์ƒ์ด๋ฉด ๋‹ฌ์„ฑ ์ฒ˜๋ฆฌ
85+
data["achieved"][ctype] = (count >= goal)
86+
87+
# 5. ์Šค์ฝ”์–ด๋ณด๋“œ ์ €์žฅ
88+
with open(SCOREBOARD_FILE, 'w', encoding='utf-8') as f:
89+
json.dump(scoreboard, f, ensure_ascii=False, indent=2)
90+
91+
print("scoreboard.json ์—…๋ฐ์ดํŠธ ์™„๋ฃŒ!")
92+
93+
if __name__ == '__main__':
94+
main()

0 commit comments

Comments
ย (0)