-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathUpdate.sh
More file actions
executable file
·168 lines (118 loc) · 4.65 KB
/
Copy pathUpdate.sh
File metadata and controls
executable file
·168 lines (118 loc) · 4.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#!/usr/bin/env bash
export PATH="/usr/local/bin:/opt/homebrew/bin:$PATH"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Function to print colored output
print_status() {
\echo -e "${BLUE}[STATUS]${NC} $1"
}
print_success() {
\echo -e "${GREEN}[SUCCESS]${NC} $1"
}
print_error() {
\echo -e "${RED}[ERROR]${NC} $1"
}
print_warning() {
\echo -e "${YELLOW}[WARNING]${NC} $1"
}
print_status "Starting Update.sh script"
# Find workflow .yml/.yaml files, ignoring common non-source directories
\find . -type d \( -iname node_modules -o -iname vendor -o -iname dist -o -iname target -o -iname \.git -o -iname \.next -o -iname \.venv \) -prune -false -o -type f \( -name "*.yml" -o -name "*.yaml" \) -print0 | while IFS= read -r -d $'\0' file; do
print_status "Processing file: $file"
temp_file=$(\mktemp)
while IFS= read -r line; do
if [[ "$line" =~ uses:\ [^[:space:]]+ ]]; then
print_status "Found uses in $file: $line"
# Extract the full action reference (no surrounding quotes, no existing # comment)
action_part=$(\echo "$line" | \sed -E 's/.*uses:\ ([^[:space:]"'\'']+).*/\1/' | \sed -E 's/\s*#.*//')
print_status "Action part: $action_part"
# Split into action_name and current_reference
if [[ "$action_part" == *@* ]]; then
action_name=$(\echo "$action_part" | \cut -d '@' -f 1)
current_reference=$(\echo "$action_part" | \cut -d '@' -f 2)
print_status "Current reference: $current_reference"
else
action_name="$action_part"
current_reference=""
print_status "No reference specified"
fi
IFS='/' read -r -a parts <<<"$action_name"
if [ ${#parts[@]} -lt 2 ]; then
print_error "Invalid action name: $action_name"
\echo "$line" >>"$temp_file"
continue
fi
repo_part="${parts[0]}/${parts[1]}"
path_part=$(
IFS='/'
\echo "${parts[@]:2}"
)
print_status "Repo: $repo_part, Path: $path_part"
if [[ "$repo_part" == ./* || "$repo_part" == ./. ]]; then
print_warning "Skipping local action: $action_part"
\echo "$line" >>"$temp_file"
continue
fi
# Get the latest tag - use the newest semantic version from ALL tags,
# not just tags[0] (the API returns tags in an arbitrary order).
latest_tag=$(\gh api "repos/$repo_part/tags?per_page=100" | \jq -r '.[].name' |
\grep -E '^v?[0-9]+\.[0-9]+\.[0-9]+$' |
\sed 's/^v//' | \sort -V | tail -1 | \sed 's/^/v/')
if [ -z "$latest_tag" ] || [ "$latest_tag" = "v" ]; then
# Fallback: no semver tags found, take the first available tag.
latest_tag=$(\gh api "repos/$repo_part/tags" | \jq -r '.[0].name')
fi
if [ -z "$latest_tag" ] || [ "$latest_tag" == "null" ]; then
print_error "Failed to get tag for $repo_part"
\echo "$line" >>"$temp_file"
continue
fi
print_status "Latest tag: $latest_tag"
# Resolve the tag ref to a SHA. For ANNOTATED tags, ref.object.sha is the
# tag-object SHA, NOT the commit. Follow it to the real commit SHA, which
# is what GitHub Actions requires in `uses:`.
ref_json=$(\gh api "repos/$repo_part/git/ref/tags/$latest_tag")
if [ -z "$ref_json" ] || [ "$ref_json" == "null" ]; then
print_error "Failed to resolve ref for $repo_part @ $latest_tag"
\echo "$line" >>"$temp_file"
continue
fi
obj_type=$(\echo "$ref_json" | \jq -r '.object.type')
obj_sha=$(\echo "$ref_json" | \jq -r '.object.sha')
if [ "$obj_type" = "tag" ]; then
# Annotated tag: the object is itself a tag; fetch its commit.
commit_sha=$(\gh api "repos/$repo_part/git/tags/$obj_sha" | \jq -r '.object.sha')
else
# Lightweight tag: the object is the commit directly.
commit_sha="$obj_sha"
fi
if [ -z "$commit_sha" ] || [ "$commit_sha" == "null" ]; then
print_error "Failed to resolve commit SHA for $repo_part @ $latest_tag"
\echo "$line" >>"$temp_file"
continue
fi
print_status "Commit SHA: $commit_sha"
# Build the new action reference: action@sha # tag
if [ -n "$path_part" ]; then
new_action_part="${repo_part}/${path_part}@${commit_sha} # ${latest_tag}"
else
new_action_part="${repo_part}@${commit_sha} # ${latest_tag}"
fi
print_status "New action part: $new_action_part"
# Use sed to replace the entire uses: reference including any existing comments
# This handles: @tag, @sha # oldcomment, @sha # old1 # old2, etc.
new_line=$(\echo "$line" | \sed -E 's|(uses:\s+)[^[:space:]"'\'']+.*|\1'"${new_action_part}"'|')
print_success "→ ${new_line}"
\echo "$new_line" >>"$temp_file"
else
\echo "$line" >>"$temp_file"
fi
done <"$file"
\mv "$temp_file" "$file"
print_success "Updated $file"
done
print_status "Update complete"