Skip to content

Instantly share code, notes, and snippets.

@wallentx
Created June 8, 2023 04:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wallentx/500e911c040b9caafe7f94eabb0adc70 to your computer and use it in GitHub Desktop.
Save wallentx/500e911c040b9caafe7f94eabb0adc70 to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash
set -euo pipefail
download_dir="."
TMPOUT=$(mktemp /tmp/tmpXXXXXXXXXX)
while getopts ":d:v" opt; do
case ${opt} in
d)
download_dir=$OPTARG
;;
v)
set -x
;;
\?)
echo "Invalid Option: -$OPTARG" 1>&2
exit 1
;;
:)
echo "Option -$OPTARG requires an argument." 1>&2
exit 1
;;
esac
done
shift $((OPTIND -1))
function shutdown() {
tput cnorm
rm "$TMPOUT"
}
trap shutdown EXIT
function _cursorBack() {
echo -en "\033[$1D"
}
function _spinner() {
local LC_CTYPE=C
local LC_ALL=en_US.utf-8
tput civis
local CL="\e[2K"
local spin="⣷⣯⣟⡿⢿⣻⣽⣾"
local pid=$(jobs -p)
local charwidth=1
local i=0
while kill -0 $pid 2>/dev/null; do
local i=$(((i + charwidth) % ${#spin}))
printf "%s" "$(tput setaf 2)${spin:i:charwidth}$(tput sgr0)"
_cursorBack 1
sleep .1
done
echo -ne "$CL"
tput cnorm
wait $(jobs -p)
}
Coff='\e[0m' # Off
Green='\e[0;32m' # Green
Blue='\e[0;34m' # Blue
Yellow='\e[0;33m' # Yellow
Purple='\e[0;35m' # Purple
BIBlack='\e[1;90m' # Bold Intense Black
echo -ne "${Yellow}Parsing workflows...${Coff}"
# Check if an array contains an element
function containsElement () {
local e match="$1"
shift
for e; do [[ "$e" == "$match" ]] && return 0; done
return 1
}
# Parse the URL
url=$1
repo_owner=$(echo "$url" | cut -d'/' -f4)
repo_name=$(echo "$url" | cut -d'/' -f5)
pr_number=$(echo "$url" | cut -d'/' -f7)
# Get PR details to find the branch name
pr_details=$(gh api repos/"$repo_owner/$repo_name/pulls/$pr_number")
branch_name=$(echo "$pr_details" | jq -r '.head.ref')
# Get the workflow runs for the PR branch
workflow_runs=$(gh api repos/"$repo_owner/$repo_name"/actions/runs?branch="$branch_name")
# Create array to store processed workflows
processed_workflows=()
# Create associative arrays to store artifact details
declare -A artifact_names
declare -A artifact_sizes
# Prepare a list of all relevant workflows and their artifacts
workflows_with_artifacts=()
while read -r line; do
# Get workflow name and run id from link
workflow_name=$(echo "$line" | rev | cut -d' ' -f2- | rev )
run_id=$(echo "$line" | rev | cut -d' ' -f1 | rev)
# Skip if this workflow is already processed
if containsElement "$workflow_name" "${processed_workflows[@]}"; then
continue
fi
# Get workflow run status
# run_status=$(echo "$workflow_runs" | jq -r ".workflow_runs[] | select(.id == $run_id) | .status")
# If the run status is 'pending' or 'in_progress', inform the user
# if [[ "$run_status" == "pending" ]] || [[ "$run_status" == "in_progress" ]]; then
# echo "Warning: Workflow run $run_id is currently $run_status."
# fi
# List the artifacts for the run
export artifacts=$(gh api repos/"$repo_owner/$repo_name/actions/runs/$run_id"/artifacts | jq -r '.artifacts[] | .name')
# Only count this workflow if it has at least one artifact
if [ "$artifacts" != "" ]; then
workflows_with_artifacts+=("$workflow_name#$run_id")
processed_workflows+=("$workflow_name")
fi
done < <(echo "$workflow_runs" | jq -r '.workflow_runs[] | select(.name != null) | "\(.name) \(.id)"' | sort -r)
#done < <(echo "$workflow_runs" | jq -r '.workflow_runs[] | select(.name != null) and (.status != "in_progress") and (.status != "queued") | "\(.name) \(.id)"' | sort -r)
# Count the total number of workflows with artifacts
total_workflows=${#workflows_with_artifacts[@]}
# Iterate over each workflow with artifacts
printf '\r'
echo -e "${Blue}Artifacts for PR${Green} #${Purple}$pr_number${Coff}:"
current_workflow=1
for workflow_with_artifact in "${workflows_with_artifacts[@]}"; do
# Get workflow name and run id from line
export workflow_name=$(echo "$workflow_with_artifact" | cut -d'#' -f1)
export run_id=$(echo "$workflow_with_artifact" | cut -d'#' -f2)
# List the artifacts for the run
export artifacts=$(gh api repos/"$repo_owner/$repo_name/actions/runs/$run_id"/artifacts)
# Check if we're at the last workflow
if [[ $current_workflow -eq $total_workflows ]]; then
echo -e "└──${BIBlack}$workflow_name:${Coff}"
else
echo -e "├──${BIBlack}$workflow_name:${Coff}"
fi
# Iterate over artifacts and echo name
while read -r artifact; do
name=$(echo "$artifact" | jq -r '.name')
size=$(echo "$artifact" | jq -r '.size_in_bytes')
download_url=$(echo "$artifact" | jq -r '.archive_download_url')
artifact_names[$name]=$download_url
artifact_sizes[$name]=$size
if [[ $current_workflow -eq $total_workflows ]]; then
echo " └──📦$name"
else
echo "│ └──📦$name"
fi
done < <(echo "$artifacts" | jq -c '.artifacts[]')
if [[ $current_workflow -ne $total_workflows ]]; then
echo "│"
fi
# Increment the current workflow counter
current_workflow=$((current_workflow + 1))
done
function getArtifact() {
gh \
api \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"$download_url" > "$download_dir/$artifact_name.zip"
}
function execInfo() {
getArtifact >"$TMPOUT" &
_spinner
echo -ne "\r"
cat "$TMPOUT"
}
function select_artifacts() {
local artifact_names_list=("$@")
local num_artifacts=${#artifact_names_list[@]}
local selected_artifacts=()
if [[ $num_artifacts -eq 0 ]]; then
echo "No artifacts"
exit 0
fi
echo "
"
echo -e "${Green}== Artifacts to download ==${Coff}"
for ((i=0; i<num_artifacts; i++)); do
echo -e "${Purple}$((i+1)) ${Yellow}${artifact_names_list[i]}${Coff}"
done
echo -e "${Green}==> ${Blue}Enter the numbers of the artifacts you want to download ${Yellow}(e.g., '1 2 3', '1-3' or '^4')${Coff}"
echo -ne "${Green}==>${Coff}"
read -rp " " input
if [[ $input == *'-'* ]]; then
IFS='-' read -ra RANGE <<< "$input"
for ((i=RANGE[0]; i<=RANGE[1]; i++)); do
selected_artifacts+=("${artifact_names_list[i-1]}")
done
elif [[ $input == *'^'* ]]; then
IFS='^' read -ra EXCLUDE <<< "$input"
for ((i=1; i<=num_artifacts; i++)); do
if [[ $i != "${EXCLUDE[1]}" ]]; then
selected_artifacts+=("${artifact_names_list[i-1]}")
fi
done
else
# shellcheck disable=SC2068
for i in ${input[@]}; do
selected_artifacts+=("${artifact_names_list[i-1]}")
done
fi
# Download selected artifacts
for artifact in "${selected_artifacts[@]}"; do
artifact_name=$(echo "$artifact" | cut -d' ' -f1)
download_url="${artifact_names[$artifact_name]}"
echo -ne "${Blue}Downloading ${Yellow}$artifact_name.zip${Coff}... "
execInfo
echo -e "${Blue}Download complete!${Coff}"
done
}
# Populate an array of artifacts
artifact_list=()
for artifact_name in "${!artifact_names[@]}"; do
artifact_size_bytes=${artifact_sizes[$artifact_name]}
artifact_list+=("$artifact_name ($(echo "$artifact_size_bytes" | awk '{ byte =$1 /1024/1024; print byte " MB" }'))")
done
select_artifacts "${artifact_list[@]}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment