Просмотр исходного кода

enh: contributions stats script

Timothy Jaeryang Baek 5 месяцев назад
Родитель
Сommit
b1fb298bee
2 измененных файлов с 74 добавлено и 64 удалено
  1. 0 64
      Caddyfile.localhost
  2. 74 0
      contribution_stats.py

+ 0 - 64
Caddyfile.localhost

@@ -1,64 +0,0 @@
-# Run with
-#    caddy run --envfile ./example.env --config ./Caddyfile.localhost
-#
-# This is configured for
-#    - Automatic HTTPS (even for localhost)
-#    - Reverse Proxying to Ollama API Base URL (http://localhost:11434/api)
-#    - CORS
-#    - HTTP Basic Auth API Tokens (uncomment basicauth section)
-
-
-# CORS Preflight (OPTIONS) + Request (GET, POST, PATCH, PUT, DELETE)
-(cors-api) {
-	@match-cors-api-preflight method OPTIONS
-	handle @match-cors-api-preflight {
-		header {
-			Access-Control-Allow-Origin "{http.request.header.origin}"
-			Access-Control-Allow-Methods "GET, POST, PUT, PATCH, DELETE, OPTIONS"
-			Access-Control-Allow-Headers "Origin, Accept, Authorization, Content-Type, X-Requested-With"
-			Access-Control-Allow-Credentials "true"
-			Access-Control-Max-Age "3600"
-			defer
-		}
-		respond "" 204
-	}
-
-	@match-cors-api-request {
-		not {
-			header Origin "{http.request.scheme}://{http.request.host}"
-		}
-		header Origin "{http.request.header.origin}"
-	}
-	handle @match-cors-api-request {
-		header {
-			Access-Control-Allow-Origin "{http.request.header.origin}"
-			Access-Control-Allow-Methods "GET, POST, PUT, PATCH, DELETE, OPTIONS"
-			Access-Control-Allow-Headers "Origin, Accept, Authorization, Content-Type, X-Requested-With"
-			Access-Control-Allow-Credentials "true"
-			Access-Control-Max-Age "3600"
-			defer
-		}
-	}
-}
-
-# replace localhost with example.com or whatever
-localhost {
-	## HTTP Basic Auth
-	## (uncomment to enable)
-	# basicauth {
-	# 	# see .example.env for how to generate tokens
-	# 	{env.OLLAMA_API_ID} {env.OLLAMA_API_TOKEN_DIGEST}
-	# }
-
-	handle /api/* {
-		# Comment to disable CORS
-		import cors-api
-
-		reverse_proxy localhost:11434
-	}
-
-	# Same-Origin Static Web Server
-	file_server {
-		root ./build/
-	}
-}

+ 74 - 0
contribution_stats.py

@@ -0,0 +1,74 @@
+import os
+import subprocess
+from collections import Counter
+
+CONFIG_FILE_EXTENSIONS = (".json", ".yml", ".yaml", ".ini", ".conf", ".toml")
+
+
+def is_text_file(filepath):
+    # Check for binary file by scanning for null bytes.
+    try:
+        with open(filepath, "rb") as f:
+            chunk = f.read(4096)
+        if b"\0" in chunk:
+            return False
+        return True
+    except Exception:
+        return False
+
+
+def should_skip_file(path):
+    base = os.path.basename(path)
+    # Skip dotfiles and dotdirs
+    if base.startswith("."):
+        return True
+    # Skip config files by extension
+    if base.lower().endswith(CONFIG_FILE_EXTENSIONS):
+        return True
+    return False
+
+
+def get_tracked_files():
+    try:
+        output = subprocess.check_output(["git", "ls-files"], text=True)
+        files = output.strip().split("\n")
+        files = [f for f in files if f and os.path.isfile(f)]
+        return files
+    except subprocess.CalledProcessError:
+        print("Error: Are you in a git repository?")
+        return []
+
+
+def main():
+    files = get_tracked_files()
+    email_counter = Counter()
+    total_lines = 0
+
+    for file in files:
+        if should_skip_file(file):
+            continue
+        if not is_text_file(file):
+            continue
+        try:
+            blame = subprocess.check_output(
+                ["git", "blame", "-e", file], text=True, errors="replace"
+            )
+            for line in blame.splitlines():
+                # The email always inside <>
+                if "<" in line and ">" in line:
+                    try:
+                        email = line.split("<")[1].split(">")[0].strip()
+                    except Exception:
+                        continue
+                    email_counter[email] += 1
+                    total_lines += 1
+        except subprocess.CalledProcessError:
+            continue
+
+    for email, lines in email_counter.most_common():
+        percent = (lines / total_lines * 100) if total_lines else 0
+        print(f"{email}: {lines} {percent:.2f}%")
+
+
+if __name__ == "__main__":
+    main()