196 lines
4.2 KiB
Bash
Executable file
196 lines
4.2 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:-}"
|
|
|
|
if [[ "$WORKSPACE_ROOT" != "/" ]]; then
|
|
WORKSPACE_ROOT="${WORKSPACE_ROOT%/}"
|
|
fi
|
|
|
|
TARGET_REPOS=(
|
|
"agent-shell"
|
|
"agent-framework"
|
|
"iop"
|
|
"nexo"
|
|
"oto"
|
|
"proto-socket"
|
|
)
|
|
|
|
resolve_repo_rel() {
|
|
local requested="$1"
|
|
|
|
if [[ -d "$WORKSPACE_ROOT/$requested/.git" ]]; then
|
|
printf '%s\n' "$requested"
|
|
return 0
|
|
fi
|
|
|
|
if [[ "$requested" == "agent-framework" && -d "$WORKSPACE_ROOT/agentic-framework/.git" ]]; then
|
|
printf '%s\n' "agentic-framework"
|
|
return 0
|
|
fi
|
|
|
|
return 1
|
|
}
|
|
|
|
is_sync_path() {
|
|
local path="$1"
|
|
|
|
case "$path" in
|
|
agent-ops/*|.claude/*|AGENTS.md|GEMINI.md|CLAUDE.md|.cursorrules|.clinerules)
|
|
return 0
|
|
;;
|
|
esac
|
|
|
|
return 1
|
|
}
|
|
|
|
includes_all_changes() {
|
|
local requested="$1"
|
|
local rel="$2"
|
|
|
|
[[ "$requested" == "agent-framework" || "$rel" == "agent-framework" || "$rel" == "agentic-framework" ]]
|
|
}
|
|
|
|
commit_paths() {
|
|
local repo="$1"
|
|
local sha="$2"
|
|
|
|
git -C "$repo" diff-tree --root --no-commit-id --name-only -r "$sha"
|
|
}
|
|
|
|
is_summary_commit() {
|
|
local repo="$1"
|
|
local sha="$2"
|
|
local path
|
|
|
|
while IFS= read -r path; do
|
|
[[ -z "$path" ]] && continue
|
|
if ! is_sync_path "$path"; then
|
|
return 0
|
|
fi
|
|
done < <(commit_paths "$repo" "$sha")
|
|
|
|
return 1
|
|
}
|
|
|
|
path_bucket() {
|
|
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
|
|
}
|
|
'
|
|
}
|
|
|
|
shortstat_for_commits() {
|
|
local repo="$1"
|
|
shift
|
|
local sha
|
|
|
|
for sha in "$@"; do
|
|
git -C "$repo" show --shortstat --pretty=tformat: "$sha"
|
|
done |
|
|
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
|
|
}
|
|
'
|
|
}
|
|
|
|
log_args=(--branches --remotes --since="$SINCE")
|
|
if [[ -n "$UNTIL" ]]; then
|
|
log_args+=(--until="$UNTIL")
|
|
fi
|
|
|
|
for requested in "${TARGET_REPOS[@]}"; do
|
|
if ! rel="$(resolve_repo_rel "$requested")"; then
|
|
continue
|
|
fi
|
|
|
|
repo="$WORKSPACE_ROOT/$rel"
|
|
mapfile -t all_shas < <(git -C "$repo" log "${log_args[@]}" --format='%H' | sort -u)
|
|
((${#all_shas[@]} > 0)) || continue
|
|
|
|
summary_shas=()
|
|
if includes_all_changes "$requested" "$rel"; then
|
|
summary_shas=("${all_shas[@]}")
|
|
else
|
|
for sha in "${all_shas[@]}"; do
|
|
if is_summary_commit "$repo" "$sha"; then
|
|
summary_shas+=("$sha")
|
|
fi
|
|
done
|
|
fi
|
|
|
|
((${#summary_shas[@]} > 0)) || continue
|
|
|
|
echo "## $rel"
|
|
if [[ "$requested" != "$rel" ]]; then
|
|
echo "requested_alias: $requested"
|
|
fi
|
|
|
|
printf 'branch: '
|
|
git -C "$repo" branch --show-current
|
|
|
|
echo "total_commits_in_period: ${#all_shas[@]}"
|
|
echo "summary_commits: ${#summary_shas[@]}"
|
|
|
|
authors="$(git -C "$repo" show --no-patch --format='%aN <%aE>' "${summary_shas[@]}" | 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" show --no-patch --date=iso --format='%h | %ad | %s' "${summary_shas[@]}"
|
|
echo
|
|
|
|
if includes_all_changes "$requested" "$rel"; then
|
|
echo "top paths:"
|
|
for sha in "${summary_shas[@]}"; do
|
|
commit_paths "$repo" "$sha"
|
|
done |
|
|
path_bucket |
|
|
sort -nr |
|
|
head -n 16
|
|
else
|
|
echo "top non-sync paths:"
|
|
for sha in "${summary_shas[@]}"; do
|
|
while IFS= read -r path; do
|
|
[[ -z "$path" ]] && continue
|
|
if ! is_sync_path "$path"; then
|
|
printf '%s\n' "$path"
|
|
fi
|
|
done < <(commit_paths "$repo" "$sha")
|
|
done |
|
|
path_bucket |
|
|
sort -nr |
|
|
head -n 16
|
|
fi
|
|
|
|
echo "shortstat:"
|
|
shortstat_for_commits "$repo" "${summary_shas[@]}"
|
|
echo
|
|
done
|