bsc

Comprehensive codebase and cou...
Log | Files | Refs | Activity | README | LICENSE

commit e31382fabbeb9b957963f4e89f07f9ec41693607
parent 8eb84fabd7a714c26f97dfa87ff3f1543e609b03
Author: Amit Dutta <mail@amit.is-a.dev>
Date:   Thu, 20 Aug 2026 13:19:07 +0530

Merge pull request #54 from notamitgamer/feat/detailed-changelog

feat: detailed changelog with per-commit file diffs
Diffstat:
M.github/workflows/main.yml | 3++-
Mchangelog.py | 174++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
2 files changed, 148 insertions(+), 29 deletions(-)

diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml @@ -91,7 +91,8 @@ jobs: BUILD_REF: ${{ github.ref_name }} BUILD_TIMESTAMP: ${{ github.event.head_commit.timestamp }} run: | - git log --pretty=format:"%H|%s|%an|%aI" -20 > git_log.txt + git log -10 --pretty=format:"COMMIT|%H|%s|%an|%aI" --numstat > git_log_numstat.txt + git log -10 --pretty=format:"COMMIT|%H" --name-status > git_log_namestatus.txt python changelog.py - name: Commit generated changelog to repo diff --git a/changelog.py b/changelog.py @@ -9,41 +9,160 @@ timestamp = os.environ.get('BUILD_TIMESTAMP', '') try: dt = datetime.fromisoformat(timestamp).astimezone(timezone.utc) build_time = dt.strftime('%B %d, %Y at %H:%M UTC') -except: +except Exception: build_time = timestamp -# Parse git log +STATUS_LABELS = { + 'A': 'Added', + 'M': 'Modified', + 'D': 'Removed', + 'T': 'Type changed', + 'U': 'Unmerged', +} + + +def status_label(code): + letter = code[0] + if letter == 'R': + return f'Renamed ({code[1:]}%)' if len(code) > 1 else 'Renamed' + if letter == 'C': + return f'Copied ({code[1:]}%)' if len(code) > 1 else 'Copied' + return STATUS_LABELS.get(letter, letter) + + +# ---- Pass 1: commit metadata + numstat (line/diff counts) ---- commits = [] +commit_index = {} # full_sha -> index in commits + try: - with open('git_log.txt', 'r', encoding='utf-8') as f: - for line in f: - parts = line.strip().split('|') - if len(parts) == 4: - c_sha, c_msg, c_author, c_time = parts - try: - c_dt = datetime.fromisoformat(c_time).astimezone(timezone.utc) - c_time_fmt = c_dt.strftime('%b %d, %Y %H:%M UTC') - except: - c_time_fmt = c_time - commits.append({ - 'sha': c_sha[:7], - 'full_sha': c_sha, - 'msg': c_msg, - 'author': c_author, - 'time': c_time_fmt, - }) + with open('git_log_numstat.txt', 'r', encoding='utf-8') as f: + current = None + for raw_line in f: + line = raw_line.rstrip('\n') + if line.startswith('COMMIT|'): + parts = line.split('|') + if len(parts) == 5: + _, c_sha, c_msg, c_author, c_time = parts + try: + c_dt = datetime.fromisoformat(c_time).astimezone(timezone.utc) + c_time_fmt = c_dt.strftime('%b %d, %Y %H:%M UTC') + except Exception: + c_time_fmt = c_time + current = { + 'sha': c_sha[:7], + 'full_sha': c_sha, + 'msg': c_msg, + 'author': c_author, + 'time': c_time_fmt, + 'files': {}, # path -> {'add': int, 'del': int, 'status': str} + 'order': [], # preserve file order + } + commit_index[c_sha] = len(commits) + commits.append(current) + continue + if not line.strip() or current is None: + continue + # numstat line: "<added>\t<deleted>\t<path>" (binary files use '-') + cols = line.split('\t') + if len(cols) == 3: + add, dele, path = cols + add_n = int(add) if add.isdigit() else 0 + del_n = int(dele) if dele.isdigit() else 0 + current['files'][path] = {'add': add_n, 'del': del_n, 'status': 'M'} + current['order'].append(path) +except FileNotFoundError: + pass + +# ---- Pass 2: name-status (A/M/D/R/C) merged into the same commits ---- +try: + with open('git_log_namestatus.txt', 'r', encoding='utf-8') as f: + current = None + for raw_line in f: + line = raw_line.rstrip('\n') + if line.startswith('COMMIT|'): + parts = line.split('|') + if len(parts) == 2: + c_sha = parts[1] + idx = commit_index.get(c_sha) + current = commits[idx] if idx is not None else None + continue + if not line.strip() or current is None: + continue + cols = line.split('\t') + if len(cols) == 2: + code, path = cols + if path in current['files']: + current['files'][path]['status'] = code + else: + current['files'][path] = {'add': 0, 'del': 0, 'status': code} + current['order'].append(path) + elif len(cols) == 3: + code, old_path, new_path = cols + target = new_path + stats = current['files'].pop(old_path, {'add': 0, 'del': 0, 'status': code}) + stats['status'] = code + current['files'][target] = stats + if old_path in current['order']: + current['order'][current['order'].index(old_path)] = target + else: + current['order'].append(target) except FileNotFoundError: pass ICON = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="display:inline; margin-bottom:-2px; margin-right:6px;" class="lucide lucide-history"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/><path d="M12 7v5l4 2"/></svg>' -# Build commit history markdown -commit_lines = [] -for c in commits: - commit_url = f"https://github.com/notamitgamer/bsc/commit/{c['full_sha']}" - commit_lines.append(f"- [`{c['sha']}`]({commit_url}) {c['msg']} — {c['author']}, {c['time']}") -commit_section = '\n'.join(commit_lines) if commit_lines else '- No commit history available.' +def build_commit_block(c): + commit_url = f"https://github.com/notamitgamer/bsc/commit/{c['full_sha']}" + total_add = sum(v['add'] for v in c['files'].values()) + total_del = sum(v['del'] for v in c['files'].values()) + file_count = len(c['files']) + + header = ( + f"### [`{c['sha']}`]({commit_url}) {c['msg']}\n\n" + f"**{c['author']}** committed on {c['time']}" + ) + + if file_count: + stat_bits = [] + if total_add or total_del: + stat_bits.append(f"+{total_add} / -{total_del} lines") + stat_bits.append(f"{file_count} file{'s' if file_count != 1 else ''} changed") + header += f" · {' · '.join(stat_bits)}" + + if not file_count: + return header + "\n" + + file_lines = [] + for path in c['order']: + info = c['files'][path] + label = status_label(info['status']) + diff_bits = [] + if info['add']: + diff_bits.append(f"+{info['add']}") + if info['del']: + diff_bits.append(f"-{info['del']}") + diff_str = ' '.join(diff_bits) if diff_bits else 'binary/no diff' + file_lines.append(f"| `{path}` | {label} | {diff_str} |") + + files_table = ( + "| File | Change | Lines |\n" + "| --- | --- | --- |\n" + + '\n'.join(file_lines) + ) + + details = ( + "<details>\n" + f"<summary>Show {file_count} changed file{'s' if file_count != 1 else ''}</summary>\n\n" + f"{files_table}\n" + "</details>\n" + ) + + return f"{header}\n\n{details}" + + +commit_blocks = [build_commit_block(c) for c in commits] +commit_section = '\n\n---\n\n'.join(commit_blocks) if commit_blocks else 'No commit history available.' # VitePress docs/changelog.md docs_content = f"""--- @@ -55,7 +174,7 @@ description: 'Current build information and recent commit history.' ::: tip Important Compare the Build ID (listed below) against the one in the [GitHub Changelog](https://github.com/notamitgamer/bsc/blob/main/CHANGELOG.md#latest-build) to verify that your browser is displaying the latest version. -::: +::: - **Build ID** — <span style="word-break: break-all;">`{sha}`</span> - **Triggered by** — [@{actor}](https://github.com/{actor}) @@ -95,4 +214,4 @@ root_content = f"""# Changelog with open('CHANGELOG.md', 'w', encoding='utf-8') as f: f.write(root_content) -print(f"Generated changelog with {len(commits)} commits.")- \ No newline at end of file +print(f"Generated changelog with {len(commits)} commits.")
© notamitgamer • Site Built: 2026-09-05 01:53:16 UTC • git-mirror commit: c170d72 [view raw info]
Originally created with stagit • modified by notamitgamer
Forked from github.com/notamitgamer/git-mirror