mirror of
https://github.com/hanzoai/pack.git
synced 2026-11-02 13:32:48 +00:00
* feat: add task to check and update GitHub Action versions * Automate discovery of pinned GitHub Actions in workflows. * Add interactive prompt to update actions to their latest release SHAs using the GitHub CLI. * Improve maintenance efficiency by centralizing action dependency management. Generated-by: aiautocommit * feat(chore): enhance GitHub action update script with UI and automation - Refactor the action check script to include color-coded CLI output and a summary view. - Add interactive prompts to apply updates directly to workflow files. - Improve script robustness by adding error handling for missing tags or resolutions. Generated-by: aiautocommit * chore: update github actions versions - Bump action versions across all workflows to utilize the latest dependencies and security patches. Generated-by: aiautocommit
155 lines
4.8 KiB
Bash
Executable File
155 lines
4.8 KiB
Bash
Executable File
#!/usr/bin/env zsh
|
|
# Description: check and interactively update all used GitHub Actions.
|
|
# Matches both SHA-pinned (@sha) and tag-pinned (@v3) actions.
|
|
|
|
set -euo pipefail
|
|
|
|
typeset -g c_reset c_bold c_dim c_green c_yellow c_red c_cyan c_blue
|
|
|
|
init_colors() {
|
|
if [[ -t 1 ]] && [[ -z "${NO_COLOR:-}" ]] && [[ "${TERM:-}" != "dumb" ]]; then
|
|
autoload -U colors && colors
|
|
c_reset=$reset_color
|
|
c_bold=$bold_color
|
|
c_dim=$'\e[2m'
|
|
c_green=$fg[green]
|
|
c_yellow=$fg[yellow]
|
|
c_red=$fg[red]
|
|
c_cyan=$fg[cyan]
|
|
c_blue=$fg[blue]
|
|
else
|
|
c_reset=''
|
|
c_bold=''
|
|
c_dim=''
|
|
c_green=''
|
|
c_yellow=''
|
|
c_red=''
|
|
c_cyan=''
|
|
c_blue=''
|
|
fi
|
|
}
|
|
|
|
print_rule() {
|
|
echo "${c_dim}────────────────────────────────────────────────────────${c_reset}"
|
|
}
|
|
|
|
format_ref() {
|
|
local ref=$1
|
|
if [[ ${#ref} -ge 40 ]] && [[ "$ref" =~ ^[0-9a-fA-F]+$ ]]; then
|
|
echo "${ref:0:7}…"
|
|
else
|
|
echo "$ref"
|
|
fi
|
|
}
|
|
|
|
prompt_update() {
|
|
local repo=$1 ref=$2 latest_sha=$3
|
|
if [[ -t 0 ]] && [[ -r /dev/tty ]]; then
|
|
echo -n " ${c_bold}Update${c_reset} ${c_dim}@${ref}${c_reset} ${c_dim}→${c_reset} ${c_cyan}@${latest_sha}${c_reset}? ${c_dim}(y/N)${c_reset} "
|
|
read -k 1 choice < /dev/tty
|
|
echo
|
|
[[ "$choice" == "y" || "$choice" == "Y" ]]
|
|
else
|
|
echo " ${c_dim}(non-interactive: skipped — run in a terminal to apply)${c_reset}"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
init_colors
|
|
|
|
repo_root="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
|
|
cd "$repo_root"
|
|
|
|
all_actions=$(grep -rE "uses: [^@]+@[^[:space:]]+" .github/workflows 2>/dev/null \
|
|
| sed -E 's/.*uses: ([^@]+)@([^[:space:]]+)/\1@\2/' \
|
|
| sort -u)
|
|
|
|
if [[ -z "$all_actions" ]]; then
|
|
echo "${c_yellow}No GitHub Action usages found in .github/workflows.${c_reset}"
|
|
exit 0
|
|
fi
|
|
|
|
action_count=$(echo "$all_actions" | wc -l | tr -d ' ')
|
|
repo_count=$(echo "$all_actions" | cut -d'@' -f1 | sort -u | wc -l | tr -d ' ')
|
|
|
|
echo "${c_bold}GitHub Actions update check${c_reset}"
|
|
echo "${c_dim}${repo_count} action(s), ${action_count} pin(s) in .github/workflows/${c_reset}"
|
|
echo
|
|
|
|
typeset -i count_ok=0 count_update=0 count_updated=0 count_skipped=0 count_error=0
|
|
|
|
repos=$(echo "$all_actions" | cut -d'@' -f1 | sort -u)
|
|
|
|
for repo in ${(f)repos}; do
|
|
print_rule
|
|
echo "${c_bold}${c_cyan}${repo}${c_reset}"
|
|
|
|
latest_tag=$(gh release view --repo "$repo" --json tagName --jq .tagName 2>/dev/null || true)
|
|
if [[ -z "$latest_tag" ]]; then
|
|
latest_tag=$(gh api "repos/$repo/tags" --jq '.[0].name' 2>/dev/null || true)
|
|
fi
|
|
|
|
if [[ -z "$latest_tag" ]]; then
|
|
echo " ${c_red}✗${c_reset} Could not find releases or tags"
|
|
count_error=$(( count_error + 1 ))
|
|
echo
|
|
continue
|
|
fi
|
|
|
|
latest_sha=$(gh api "repos/$repo/commits/$latest_tag" --header 'Accept: application/vnd.github.sha' 2>/dev/null || true)
|
|
|
|
if [[ -z "$latest_sha" ]]; then
|
|
echo " ${c_dim}Latest tag${c_reset} ${c_bold}${latest_tag}${c_reset}"
|
|
echo " ${c_red}✗${c_reset} Could not resolve SHA for ${latest_tag}"
|
|
count_error=$(( count_error + 1 ))
|
|
echo
|
|
continue
|
|
fi
|
|
|
|
echo " ${c_dim}Latest${c_reset} ${c_bold}${latest_tag}${c_reset} ${c_dim}→${c_reset} ${c_blue}$(format_ref "$latest_sha")${c_reset}"
|
|
echo " ${c_dim}${latest_sha}${c_reset}"
|
|
echo
|
|
|
|
current_refs=$(echo "$all_actions" | grep "^$repo@" | cut -d'@' -f2)
|
|
for ref in ${(f)current_refs}; do
|
|
local_label="$(format_ref "$ref")"
|
|
if [[ "$ref" == "$latest_sha" ]]; then
|
|
printf " ${c_green}✓${c_reset} %-12s ${c_green}up to date${c_reset}\n" "@${local_label}"
|
|
count_ok=$(( count_ok + 1 ))
|
|
else
|
|
printf " ${c_yellow}↑${c_reset} %-12s ${c_yellow}update available${c_reset}\n" "@${local_label}"
|
|
echo " ${c_dim}https://github.com/${repo}/compare/${ref}...${latest_sha}${c_reset}"
|
|
count_update=$(( count_update + 1 ))
|
|
|
|
if prompt_update "$repo" "$ref" "$latest_sha"; then
|
|
perl -i -pe "s|uses: $repo\@$ref\b|uses: $repo\@$latest_sha|g" .github/workflows/*.yml
|
|
echo " ${c_green}✓${c_reset} Updated workflow files"
|
|
count_updated=$(( count_updated + 1 ))
|
|
elif [[ -t 0 ]] && [[ -r /dev/tty ]]; then
|
|
echo " ${c_dim}⊘${c_reset} Skipped"
|
|
count_skipped=$(( count_skipped + 1 ))
|
|
else
|
|
count_skipped=$(( count_skipped + 1 ))
|
|
fi
|
|
fi
|
|
done
|
|
echo
|
|
done
|
|
|
|
print_rule
|
|
echo "${c_bold}Summary${c_reset}"
|
|
echo " ${c_green}✓${c_reset} ${count_ok} up to date"
|
|
if (( count_update > 0 )); then
|
|
echo " ${c_yellow}↑${c_reset} ${count_update} update(s) available"
|
|
fi
|
|
if (( count_updated > 0 )); then
|
|
echo " ${c_green}✓${c_reset} ${count_updated} applied"
|
|
fi
|
|
if (( count_skipped > 0 )); then
|
|
echo " ${c_dim}⊘${c_reset} ${count_skipped} skipped"
|
|
fi
|
|
if (( count_error > 0 )); then
|
|
echo " ${c_red}✗${c_reset} ${count_error} error(s)"
|
|
fi
|
|
echo
|