-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Misc: Add script for calculating totals for a MRVA run #18449
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
tausbn
merged 1 commit into
main
from
tausbn/misc-add-script-for-calculating-mrva-totals
May 1, 2025
+131
−0
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,131 @@ | ||
| import os | ||
| import subprocess | ||
| import tempfile | ||
| import argparse | ||
| from collections import defaultdict | ||
|
|
||
| help_text = """ | ||
| To use this script, pass the URL of a GitHub Gist as an argument. The Gist should contain the | ||
| exported MarkDown output of a MRVA run. | ||
|
|
||
| The script expects the query to produce an output table of the form | ||
| ``` | ||
| | header0 | header1 | header2 | header3 | ... | ||
| |----------|----------|----------|----------|---- | ||
| | message1 | value11 | value12 | value13 | ... | ||
| | message2 | value21 | value22 | value23 | ... | ||
| ... | ||
| ``` | ||
| The script will calculate the totals for each message and header, and put a table containing these | ||
| totals in the `_summary.md` file in the Gist. By default it will then commit and push these changes | ||
| to the Gist (having first displayed a diff of the changes). | ||
| """ | ||
|
|
||
| first_header = "" | ||
|
|
||
| def split_line(line): | ||
| return [item.strip() for item in line.strip('|').split('|')] | ||
|
|
||
| def parse_markdown_table(stream): | ||
| global first_header | ||
| iterator = (line.strip() for line in stream) | ||
|
|
||
| # Skip irrelevant lines until we find the header line | ||
| for line in iterator: | ||
| if line.startswith('|'): | ||
| first_header, *headers = split_line(line) | ||
| break | ||
|
|
||
| # Skip the separator line | ||
| next(iterator) | ||
|
|
||
| data_dict = {} | ||
|
|
||
| # Process the remaining lines | ||
| for line in iterator: | ||
| if line.startswith('|'): | ||
| message, *values = [value.strip('`') for value in split_line(line)] | ||
| data_dict[message] = { | ||
| headers[i]: int(value) if value.isdigit() else value | ||
| for i, value in enumerate(values) | ||
| } | ||
|
|
||
| return data_dict | ||
|
|
||
| def clone_gist(gist_url, repo_dir): | ||
| try: | ||
| subprocess.run(["gh", "gist", "clone", gist_url, repo_dir], check=True) | ||
| except subprocess.CalledProcessError: | ||
| print(f"Failed to clone the gist from {gist_url}") | ||
| subprocess.run(["rm", "-rf", repo_dir]) | ||
| exit(1) | ||
|
|
||
| def process_gist_files(repo_dir): | ||
| total_data = defaultdict(lambda: defaultdict(int)) | ||
|
|
||
| for filename in os.listdir(repo_dir): | ||
| if filename.endswith(".md") and filename != "_summary.md": | ||
| with open(os.path.join(repo_dir, filename), "r") as file: | ||
| data_dict = parse_markdown_table(file) | ||
|
|
||
| for message, values in data_dict.items(): | ||
| for header, value in values.items(): | ||
| if isinstance(value, int): | ||
| total_data[message][header] += value | ||
|
|
||
| return total_data | ||
|
|
||
| def append_totals_to_summary(total_data, repo_dir): | ||
| global first_header | ||
| summary_path = os.path.join(repo_dir, "_summary.md") | ||
| with open(summary_path, "r") as summary_file: | ||
| content = summary_file.read() | ||
|
|
||
| totals_table = "\n\n### Totals\n\n" | ||
| headers = [first_header] + list(next(iter(total_data.values())).keys()) | ||
| totals_table += "| " + " | ".join(headers) + " |\n" | ||
| totals_table += "| " + "|".join(["---"] + ["---:"] * (len(headers) - 1)) + " |\n" # Right align all but the first column | ||
| for message, values in total_data.items(): | ||
| row = [message] + [f"{values[header]:,}" for header in headers[1:]] | ||
| totals_table += "| " + " | ".join(row) + " |\n" | ||
|
|
||
| new_content = content.replace("### Summary", totals_table + "\n### Summary") | ||
|
|
||
| with open(summary_path, "w") as summary_file: | ||
| summary_file.write(new_content) | ||
|
|
||
| def commit_and_push_changes(repo_dir): | ||
| subprocess.run(["git", "add", "_summary.md"], cwd=repo_dir, check=True) | ||
| subprocess.run(["git", "commit", "-m", "Update summary with totals"], cwd=repo_dir, check=True) | ||
| subprocess.run(["git", "push"], cwd=repo_dir, check=True) | ||
|
|
||
| def show_git_diff(repo_dir): | ||
| subprocess.run(["git", "diff", "_summary.md"], cwd=repo_dir, check=True) | ||
|
|
||
| if __name__ == "__main__": | ||
| parser = argparse.ArgumentParser(description="Calculate MRVA totals from a GitHub Gist", epilog=help_text, formatter_class=argparse.RawTextHelpFormatter) | ||
| parser.add_argument("gist_url", nargs='?', help="URL of the GitHub Gist") | ||
| parser.add_argument("--keep-dir", action="store_true", help="Keep the temporary directory") | ||
|
|
||
| args = parser.parse_args() | ||
|
|
||
| if not args.gist_url: | ||
| parser.print_help() | ||
| exit(1) | ||
|
|
||
| repo_dir = tempfile.mkdtemp(dir=".") | ||
| clone_gist(args.gist_url, repo_dir) | ||
|
|
||
| total_data = process_gist_files(repo_dir) | ||
|
|
||
| append_totals_to_summary(total_data, repo_dir) | ||
|
|
||
| show_git_diff(repo_dir) | ||
|
|
||
| if input("Do you want to push the changes to the gist? (Y/n): ").strip().lower() in ['y', '']: | ||
| commit_and_push_changes(repo_dir) | ||
|
|
||
| if args.keep_dir: | ||
| print(f"Temporary directory retained at: {repo_dir}") | ||
| else: | ||
| subprocess.run(["rm", "-rf", repo_dir]) | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.