naughty-commits.sh 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. #!/usr/bin/env bash
  2. set -Eeuo pipefail
  3. fileSizeThresholdMB='2'
  4. : "${BASHBREW_CACHE:=$HOME/.cache/bashbrew}"
  5. export BASHBREW_CACHE BASHBREW_ARCH=
  6. if [ ! -d "$BASHBREW_CACHE/git" ]; then
  7. # initialize the "bashbrew cache"
  8. bashbrew --arch amd64 from --uniq --apply-constraints hello-world:linux > /dev/null
  9. fi
  10. _git() {
  11. git -C "$BASHBREW_CACHE/git" "$@"
  12. }
  13. if [ "$#" -eq 0 ]; then
  14. set -- '--all'
  15. fi
  16. imgs="$(bashbrew list --repos "$@" | sort -u)"
  17. for img in $imgs; do
  18. commits="$(
  19. bashbrew cat --format '
  20. {{- range $e := .Entries -}}
  21. {{- range $a := .Architectures -}}
  22. {{- /* force `git fetch` */ -}}
  23. {{- $froms := $.ArchDockerFroms $a $e -}}
  24. {
  25. {{- json "GitRepo" }}:{{ json ($e.ArchGitRepo $a) -}},
  26. {{- json "GitFetch" }}:{{ json ($e.ArchGitFetch $a) -}},
  27. {{- json "GitCommit" }}:{{ json ($e.ArchGitCommit $a) -}}
  28. }
  29. {{- "\n" -}}
  30. {{- end -}}
  31. {{- end -}}
  32. ' "$img" | jq -s 'unique'
  33. )"
  34. declare -A naughtyCommits=() naughtyTopCommits=() seenCommits=()
  35. length="$(jq -r 'length' <<<"$commits")"
  36. for (( i = 0; i < length; i++ )); do
  37. topCommit="$(jq -r ".[$i].GitCommit" <<<"$commits")"
  38. gitRepo="$(jq -r ".[$i].GitRepo" <<<"$commits")"
  39. gitFetch="$(jq -r ".[$i].GitFetch" <<<"$commits")"
  40. if ! _git fetch --quiet "$gitRepo" "$gitFetch:" ; then
  41. naughtyCommits[$topCommit]="unable to to fetch specified GitFetch: $gitFetch"
  42. naughtyTopCommits[$topCommit]="$topCommit"
  43. elif ! _git merge-base --is-ancestor "$topCommit" 'FETCH_HEAD'; then
  44. # check that the commit is in the GitFetch branch specified
  45. naughtyCommits[$topCommit]="is not in the specified ref GitFetch: $gitFetch"
  46. naughtyTopCommits[$topCommit]="$topCommit"
  47. fi
  48. IFS=$'\n'
  49. potentiallyNaughtyGlobs=( '**.tar**' )
  50. potentiallyNaughtyCommits=( $(_git log --diff-filter=DMT --format='format:%H' "$topCommit" -- "${potentiallyNaughtyGlobs[@]}") )
  51. unset IFS
  52. # bash 4.3 sucks (https://stackoverflow.com/a/7577209/433558)
  53. [ "${#potentiallyNaughtyCommits[@]}" -gt 0 ] || continue
  54. for commit in "${potentiallyNaughtyCommits[@]}"; do
  55. [ -z "${seenCommits[$commit]:-}" ] || break
  56. seenCommits[$commit]=1
  57. IFS=$'\n'
  58. binaryFiles=( $(
  59. _git diff-tree --no-commit-id -r --numstat --diff-filter=DMT "$commit" -- "${potentiallyNaughtyGlobs[@]}" \
  60. | grep '^-' \
  61. | cut -d$'\t' -f3- \
  62. || :
  63. ) )
  64. unset IFS
  65. # bash 4.3 sucks (https://stackoverflow.com/a/7577209/433558)
  66. [ "${#binaryFiles[@]}" -gt 0 ] || continue
  67. naughtyReasons=()
  68. for file in "${binaryFiles[@]}"; do
  69. fileSize="$(_git ls-tree -r --long "$commit" -- "$file" | awk '{ print $4 }')"
  70. fileSizeMB="$(( fileSize / 1024 / 1024 ))"
  71. if [ "$fileSizeMB" -gt "$fileSizeThresholdMB" ]; then
  72. naughtyReasons+=( "modified binary file (larger than ${fileSizeThresholdMB}MB): $file (${fileSizeMB}MB)" )
  73. fi
  74. done
  75. if [ "${#naughtyReasons[@]}" -gt 0 ]; then
  76. : "${naughtyCommits[$commit]:=}"
  77. if [ -n "${naughtyCommits[$commit]}" ]; then
  78. naughtyCommits[$commit]+=$'\n'
  79. fi
  80. IFS=$'\n'
  81. naughtyCommits[$commit]+="${naughtyReasons[*]}"
  82. unset IFS
  83. naughtyTopCommits[$commit]="$topCommit"
  84. fi
  85. done
  86. done
  87. if [ "${#naughtyCommits[@]}" -gt 0 ]; then
  88. echo " - $img:"
  89. for naughtyCommit in "${!naughtyCommits[@]}"; do
  90. naughtyReasons="${naughtyCommits[$naughtyCommit]}"
  91. naughtyTopCommit="${naughtyTopCommits[$naughtyCommit]}"
  92. if [ "$naughtyTopCommit" != "$naughtyCommit" ]; then
  93. #commitsBetween="$(_git rev-list --count "$naughtyCommit...$naughtyTopCommit")"
  94. naughtyCommit+=" (in history of $naughtyTopCommit)"
  95. fi
  96. echo " - commit $naughtyCommit:"
  97. sed -e 's/^/ - /' <<<"$naughtyReasons"
  98. done
  99. echo
  100. fi
  101. done