145 lines
3.6 KiB
Bash
Executable file
145 lines
3.6 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
WORKSPACE_ROOT="${1:-$(cd "$SCRIPT_DIR/../../../.." && pwd)}"
|
|
SINCE="${2:-7 days ago}"
|
|
UNTIL="${3:-}"
|
|
EXCLUDES_FILE="$WORKSPACE_ROOT/.workspace-ops/config/target-excludes.txt"
|
|
|
|
if [[ "$WORKSPACE_ROOT" != "/" ]]; then
|
|
WORKSPACE_ROOT="${WORKSPACE_ROOT%/}"
|
|
fi
|
|
|
|
normalized_excludes() {
|
|
local exclude
|
|
|
|
[[ -f "$EXCLUDES_FILE" ]] || return 0
|
|
|
|
while IFS= read -r exclude || [[ -n "$exclude" ]]; do
|
|
exclude="${exclude%%#*}"
|
|
exclude="${exclude#"${exclude%%[![:space:]]*}"}"
|
|
exclude="${exclude%"${exclude##*[![:space:]]}"}"
|
|
exclude="${exclude#./}"
|
|
exclude="${exclude#/}"
|
|
exclude="${exclude%/}"
|
|
|
|
[[ -z "$exclude" ]] && continue
|
|
|
|
printf '%s\n' "$exclude"
|
|
done < "$EXCLUDES_FILE"
|
|
}
|
|
|
|
is_excluded_repo() {
|
|
local rel="$1"
|
|
local exclude
|
|
|
|
while IFS= read -r exclude; do
|
|
if [[ "$rel" == "$exclude" || "$rel" == "$exclude/"* ]]; then
|
|
return 0
|
|
fi
|
|
done < <(normalized_excludes)
|
|
|
|
return 1
|
|
}
|
|
|
|
repo_paths() {
|
|
local -a find_args=(
|
|
"$WORKSPACE_ROOT"
|
|
-path "$WORKSPACE_ROOT/.git" -prune -o
|
|
-path "$WORKSPACE_ROOT/.workspace-ops" -prune -o
|
|
-path "$WORKSPACE_ROOT/.tmp" -prune -o
|
|
-path "$WORKSPACE_ROOT/.antigravitycli" -prune -o
|
|
-path "*/.agent-cache" -prune -o
|
|
-path "*/node_modules" -prune -o
|
|
-path "*/build" -prune -o
|
|
-path "*/dist" -prune -o
|
|
-path "*/.dart_tool" -prune -o
|
|
-path "*/coverage" -prune -o
|
|
)
|
|
local exclude
|
|
local gitdir
|
|
local rel
|
|
local repo
|
|
|
|
while IFS= read -r exclude; do
|
|
find_args+=(-path "$WORKSPACE_ROOT/$exclude" -prune -o)
|
|
done < <(normalized_excludes)
|
|
|
|
find_args+=(-type d -name .git -print)
|
|
|
|
find "${find_args[@]}" |
|
|
sort |
|
|
while IFS= read -r gitdir; do
|
|
repo="$(dirname "$gitdir")"
|
|
rel="${repo#$WORKSPACE_ROOT/}"
|
|
if git -C "$WORKSPACE_ROOT" check-ignore -q -- "$rel" && ! is_excluded_repo "$rel"; then
|
|
printf '%s\n' "$repo"
|
|
fi
|
|
done
|
|
}
|
|
|
|
log_args=(--branches --remotes --since="$SINCE")
|
|
if [[ -n "$UNTIL" ]]; then
|
|
log_args+=(--until="$UNTIL")
|
|
fi
|
|
|
|
while IFS= read -r repo; do
|
|
rel="${repo#$WORKSPACE_ROOT/}"
|
|
|
|
echo "## $rel"
|
|
printf 'branch: '
|
|
git -C "$repo" branch --show-current
|
|
|
|
printf 'commits: '
|
|
git -C "$repo" log "${log_args[@]}" --format='%H' | sort -u | wc -l
|
|
|
|
authors="$(git -C "$repo" log "${log_args[@]}" --format='%aN <%aE>' | sort -u)"
|
|
author_count="$(printf '%s\n' "$authors" | awk 'NF {c++} END {print c + 0}')"
|
|
echo "author_count: $author_count"
|
|
echo "authors:"
|
|
if [[ -n "$authors" ]]; then
|
|
printf '%s\n' "$authors" | sed 's/^/- /'
|
|
fi
|
|
|
|
echo "subjects:"
|
|
git -C "$repo" log "${log_args[@]}" --date=short --pretty=format:'%h | %ad | %s'
|
|
echo
|
|
|
|
echo "top paths:"
|
|
git -C "$repo" log "${log_args[@]}" --name-only --pretty=format:'' |
|
|
awk '
|
|
NF {
|
|
n = split($0, a, "/")
|
|
if (n == 1) {
|
|
p = a[1]
|
|
} else if (a[1] == "agent-task" || a[1] == "agent-roadmap" || a[1] == "agent-ops") {
|
|
p = a[1] "/" a[2]
|
|
} else {
|
|
p = a[1] "/" a[2]
|
|
}
|
|
c[p]++
|
|
}
|
|
END {
|
|
for (p in c) print c[p], p
|
|
}
|
|
' |
|
|
sort -nr |
|
|
head -n 12
|
|
|
|
echo "shortstat:"
|
|
git -C "$repo" log "${log_args[@]}" --shortstat --pretty=tformat: |
|
|
awk '
|
|
/files? changed/ {
|
|
files += $1
|
|
for (i = 1; i <= NF; i++) {
|
|
if ($i == "insertion(+)" || $i == "insertions(+)") ins += $(i - 1)
|
|
if ($i == "deletion(-)" || $i == "deletions(-)") del += $(i - 1)
|
|
}
|
|
}
|
|
END {
|
|
printf "files_changed_sum=%d insertions=%d deletions=%d\n", files, ins, del
|
|
}
|
|
'
|
|
echo
|
|
done < <(repo_paths)
|