Skip to content

Commit 3fd31f0

Browse files
authored
Update update_readme_calendar.py
1 parent 3bdba11 commit 3fd31f0

File tree

1 file changed

+57
-43
lines changed

1 file changed

+57
-43
lines changed

scripts/update_readme_calendar.py

Lines changed: 57 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -41,31 +41,29 @@ def git_subjects_for_date_and_path(date_str, path):
4141
return []
4242
return [line.strip() for line in out.splitlines() if line.strip()]
4343

44-
def latest_nonbot_commit_date_for_path(path):
44+
def latest_nonbot_commit_for_path(path):
4545
"""
46-
해당 path에 대한 '비봇' 커밋 중 가장 최근 커밋의 날짜(YYYY-MM-DD, KST 기준)를 반환.
47-
없으면 None.
46+
해당 path에 대한 '비봇' 커밋 중 가장 최근 항목의 (날짜, 커밋해시)를 반환.
47+
없으면 (None, None).
4848
"""
49-
cmd = f'git log --pretty="%ad%x09%s" --date=format-local:"%Y-%m-%d" -- "{path}" || true'
49+
# 날짜는 KST 로컬 포맷, 해시는 별도로 얻기 위해 %H 추가
50+
cmd = f'git log --pretty="%H%x09%ad%x09%s" --date=format-local:"%Y-%m-%d" -- "{path}" || true'
5051
out = run(cmd)
5152
if not out:
52-
return None
53+
return None, None
5354
for line in out.splitlines():
5455
line = line.strip()
5556
if not line:
5657
continue
57-
if "\t" in line:
58-
date_part, subject = line.split("\t", 1)
59-
else:
60-
parts = line.split(" ", 1)
61-
if len(parts) != 2:
62-
continue
63-
date_part, subject = parts
58+
parts = line.split("\t", 2)
59+
if len(parts) != 3:
60+
continue
61+
commit_hash, date_str, subject = parts
6462
subject = subject.strip()
6563
if BOT_REGEX.match(subject):
6664
continue
67-
return date_part
68-
return None
65+
return date_str, commit_hash
66+
return None, None
6967

7068
def commit_flag(date_str, name):
7169
"""
@@ -79,58 +77,74 @@ def commit_flag(date_str, name):
7977
for s in subjects_today:
8078
if not BOT_REGEX.match(s):
8179
return "O"
82-
nonbot_any_date = latest_nonbot_commit_date_for_path(path)
83-
if nonbot_any_date is not None and nonbot_any_date != date_str:
80+
nonbot_date, _ = latest_nonbot_commit_for_path(path)
81+
if nonbot_date is not None and nonbot_date != date_str:
8482
return "L"
8583
return "X"
8684

87-
# ---------- 파일 개수(그 날짜 스냅샷; 재귀 카운트) ----------
85+
# ---------- 스냅샷 & 파일 개수 (재귀) ----------
8886

8987
def commit_at_end_of_date(date_str):
9088
"""해당 날짜(KST 23:59:59)의 리포 스냅샷 커밋 해시 반환(없으면 빈 문자열)"""
9189
until = f'{date_str} 23:59:59 {TZ_OFFSET}'
9290
cmd = f'git rev-list -1 --before="{until}" HEAD || true'
9391
return run(cmd).strip()
9492

95-
def file_count_in_path_at_commit(commit, path):
93+
def count_files_recursive_at_commit(commit, base_dir):
9694
"""
97-
특정 커밋에서 path/ 디렉터리 '아래 전체(재귀)' 파일(=blob) 개수와 .gitkeep 존재 여부 반환.
98-
- git ls-tree -r --name-only {commit} -- "{base}" 로 모든 파일을 받고 base로 시작하는 것만 필터.
95+
특정 커밋에서 base_dir/ 아래의 모든 파일(=blob) 리스트와 .gitkeep 존재 여부 반환.
96+
- 출력: (파일경로목록(list[str]), has_gitkeep(bool))
9997
"""
10098
if not commit:
101-
return 0, False
102-
103-
base = path.rstrip("/") + "/"
99+
return [], False
100+
base = base_dir.rstrip("/") + "/"
104101
cmd = f'git ls-tree -r --name-only {commit} -- "{base}" || true'
105102
out = run(cmd)
106103
if not out:
107-
return 0, False
104+
return [], False
108105

109106
files = []
110107
has_gitkeep = False
111108
for line in out.splitlines():
112109
name = line.strip()
113-
if not name:
114-
continue
115-
if not name.startswith(base):
110+
if not name or not name.startswith(base):
116111
continue
117112
files.append(name)
118113
if os.path.basename(name) == ".gitkeep":
119114
has_gitkeep = True
115+
return files, has_gitkeep
120116

121-
return len(files), has_gitkeep
122-
123-
def file_req_and_status(date_str, name):
117+
def snapshot_for_display_and_goal(date_str, name, cf):
124118
"""
125-
(파일개수, 목표개수, 충족여부) 반환.
126-
목표: .gitkeep 있으면 4, 없으면 3 (해당 날짜 23:59:59 KST 스냅샷 기준)
119+
표시/판정에 사용할 '스냅샷 커밋'을 선택하고, 그 스냅샷에서:
120+
- 표시용 파일 개수(display_n): .gitkeep 제외
121+
- 목표값(m): .gitkeep 있으면 4, 없으면 3
122+
- 충족 여부(ok): (표시용이 아니라 실제 전체 파일수 >= m)
123+
반환: (display_n, m, ok)
127124
"""
128-
commit = commit_at_end_of_date(date_str)
129125
path = f"{date_str}/{name}"
130-
cnt, has_gitkeep = file_count_in_path_at_commit(commit, path)
131-
required = 4 if has_gitkeep else 3
132-
ok = cnt >= required
133-
return cnt, required, ok
126+
127+
if cf == "O":
128+
# 같은 날: 그날 끝 스냅샷
129+
commit = commit_at_end_of_date(date_str)
130+
elif cf == "L":
131+
# 레트로: 최신 비봇 커밋 스냅샷
132+
_, commit = latest_nonbot_commit_for_path(path)
133+
if not commit:
134+
# 안전망: 없으면 그날 스냅샷 시도
135+
commit = commit_at_end_of_date(date_str)
136+
else: # 'X'
137+
# 비봇 커밋 없으면 그날 스냅샷으로 계산(대개 0)
138+
commit = commit_at_end_of_date(date_str)
139+
140+
files, has_gitkeep = count_files_recursive_at_commit(commit, path)
141+
total_including_gitkeep = len(files)
142+
# 표시용 개수는 .gitkeep 제외
143+
display_n = total_including_gitkeep - (1 if any(os.path.basename(f) == ".gitkeep" for f in files) else 0)
144+
# 목표값 산정
145+
m = 4 if has_gitkeep else 3
146+
ok = total_including_gitkeep >= m
147+
return display_n, m, ok
134148

135149
# ---------- 달력 렌더링 ----------
136150

@@ -184,23 +198,24 @@ def build_month_calendar(year, month, today_kst):
184198
lines = []
185199
for name in NAMES:
186200
cf = commit_flag(date_str, name) # 'O','L','X'
187-
cnt, req, ok = file_req_and_status(date_str, name)
201+
display_n, m, ok = snapshot_for_display_and_goal(date_str, name, cf)
188202

189203
if cf == "O":
190204
dot = DOT_GREEN if ok else DOT_YELLOW
191205
elif cf == "L":
192206
dot = DOT_ORANGE if ok else DOT_YELLOW
193207
else:
194208
dot = DOT_RED
209+
# cf == 'X'일 땐 ok 의미가 없지만, 표시 일관성을 위해 (n/m) 그대로 둠.
195210

196-
pass_icon = "✅" if ok else "❌"
211+
# 👉 표시를 심플하게: "이름: 🟡 (n/m)"
197212
lines.append(
198213
f"<div style='font-size:13px'>{name}: {dot} "
199-
f"<span style='font-size:12px'>(<code>{cnt}/{req}</code> {pass_icon})</span></div>"
214+
f"(<code>{display_n}/{m}</code>)</div>"
200215
)
201216

202217
cell_html = (
203-
'<td align="center" valign="top" style="min-width:170px">'
218+
'<td align="center" valign="top" style="min-width:150px">'
204219
f'<div align="right"><sub>{d}</sub></div>'
205220
+ "".join(lines) +
206221
"</td>"
@@ -215,8 +230,7 @@ def build_month_calendar(year, month, today_kst):
215230
"🟠=다른날 커밋+목표달성, "
216231
"🟡=커밋있음+목표미달, "
217232
"🔴=커밋없음 · "
218-
"<code>n/m</code>=파일개수/목표(.gitkeep 있으면 m=4, 없으면 m=3)"
219-
"</sub>"
233+
"(표시 n은 .gitkeep 제외)</sub>"
220234
)
221235
table_html = (
222236
f"{month_title}\n\n"

0 commit comments

Comments
 (0)