Skip to content

Commit a7dcf19

Browse files
Debugging
1 parent 123a435 commit a7dcf19

1 file changed

Lines changed: 64 additions & 101 deletions

File tree

.github/workflows/cleanup-workflows.yml

Lines changed: 64 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -55,99 +55,74 @@ jobs:
5555
echo "EOF"
5656
} >> "$GITHUB_OUTPUT"
5757
58-
- name: Workflows on github
59-
id: github
60-
env:
61-
GH_TOKEN: ${{ github.token }}
62-
run: |
63-
# Note that we filter by `.github` path prefix to ensure we only get locally defined workflows.
64-
#
65-
# Examples of non-local workflows are `dependabot` and `copilot` which have paths:
66-
# - dynamic/dependabot/dependabot-updates
67-
# - dynamic/copilot-pull-request-reviewer/copilot-pull-request-reviewer
68-
WORKFLOWS=$(gh workflow list \
69-
--all \
70-
--json path \
71-
--jq '.[] | select(.path | startswith(".github")) | .path' \
72-
)
73-
printf "%s\n" $WORKFLOWS
74-
{
75-
echo "workflows<<EOF"
76-
echo "$WORKFLOWS"
77-
echo "EOF"
78-
} >> "$GITHUB_OUTPUT"
79-
8058
- name: Filter for deleted workflows
59+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
8160
id: deleted
8261
run: |
83-
# Union of `main` and `next` workflows.
84-
EXISTING_FILES=$( \
85-
printf "%s\n%s\n" \
62+
set -euo pipefail
63+
64+
# Union of `main` and `next` workflows as a JSON array
65+
EXISTING_FILES=$(printf "%s\n%s\n" \
8666
"${{ steps.main.outputs.workflows }}" \
8767
"${{ steps.next.outputs.workflows }}" \
8868
)
89-
EXISTING_FILES=$(echo "$EXISTING_FILES" | sort -u)
90-
printf "%s\n" $EXISTING_FILES
91-
92-
# Find deleted workflows as the items in `WORKFLOWS` but not in the union of main and next.
93-
# This assumes that _all_ items in main and next are present in `WORKFLOWS`.
94-
DELETED_FILES=$( \
95-
printf "%s\n%s\n" \
96-
"$EXISTING_FILES" \
97-
"${{ steps.github.outputs.workflows }}" \
69+
EXISTING_JSON=$(echo "$EXISTING_FILES" | sort -u | jq -R . | jq -s .)
70+
echo "Existing workflows JSON:"
71+
echo "$EXISTING_JSON"
72+
73+
# Get workflows currently on GitHub
74+
#
75+
# Note that we filter by `.github` path prefix to ensure we only get locally defined workflows.
76+
# Examples of non-local workflows are `dependabot` and `copilot` which have paths:
77+
# - dynamic/dependabot/dependabot-updates
78+
# - dynamic/copilot-pull-request-reviewer/copilot-pull-request-reviewer
79+
GITHUB=$(gh workflow list --all --json path,name,databaseId \
80+
--jq '.[] | select(.path | startswith(".github"))'
81+
)
82+
echo "Workflows on GitHub:"
83+
echo "$GITHUB"
84+
85+
# Find deleted workflows: in GitHub but not in existing
86+
DELETED=$(jq -c \
87+
--argjson github "$GITHUB" \
88+
--argjson existing "$EXISTING_JSON" '
89+
$github | map(select(.path as $p | $existing | index($p) | not))
90+
'
9891
)
99-
DELETED_FILES=$(echo "$DELETED_FILES" | sort | uniq -u)
100-
printf "%s\n" $DELETED_FILES
92+
echo "Deleted workflows:"
93+
echo "$DELETED"
94+
95+
# Output to GitHub Actions
10196
{
10297
echo "workflows<<EOF"
103-
echo "$DELETED_FILES"
98+
echo "$DELETED"
10499
echo "EOF"
105100
} >> "$GITHUB_OUTPUT"
106101
107102
- name: Delete runs from deleted workflows
108103
env:
109104
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
110105
MODE: ${{ inputs.mode }}
111-
DELETED_WORKFLOWS: ${{ steps.deleted.outputs.workflows }}
106+
WORKFLOWS: ${{ steps.deleted.outputs.workflows }}
112107
OWNER: ${{ github.repository_owner }}
113108
REPO: ${{ github.repository }}
114109
run: |
115110
set -euo pipefail
116111
117112
TOTAL_AFFECTED=0
118113
SUMMARY=()
119-
120-
# Read workflows into an array for indexing
121-
mapfile -t WORKFLOWS_ARRAY <<< "$DELETED_WORKFLOWS"
122-
TOTAL_WORKFLOWS=${#WORKFLOWS_ARRAY[@]}
123-
124-
# Convert workflow paths to workflow names
125-
WORKFLOW_NAMES_ARRAY=()
126-
for wf_path in "${WORKFLOWS_ARRAY[@]}"; do
127-
# Extract 'name' from YAML, fallback to filename
128-
name=$(yq -r '.name // ""' "$wf_path" 2>/dev/null || true)
129-
if [ -z "$name" ]; then
130-
name=$(basename "$wf_path")
131-
fi
132-
WORKFLOW_NAMES_ARRAY+=("$name")
133-
done
134-
135-
# Determine max workflow name length for alignment
136-
MAX_WF_LENGTH=0
137-
for wf in "${WORKFLOW_NAMES_ARRAY[@]}"; do
138-
len=${#wf}
139-
(( len > MAX_WF_LENGTH )) && MAX_WF_LENGTH=$len
140-
done
141-
(( MAX_WF_LENGTH < 30 )) && MAX_WF_LENGTH=30 # minimum width
114+
CURRENT_INDEX=0
142115
143116
# Column widths
144117
INDEX_WIDTH=9
118+
MAX_WF_LENGTH=30
145119
WORKFLOW_COUNT_WIDTH=14
146120
GLOBAL_TOTAL_WIDTH=12
147-
148-
# Total table width
149121
TOTAL_WIDTH=$(( INDEX_WIDTH + 3 + MAX_WF_LENGTH + 3 + WORKFLOW_COUNT_WIDTH + 3 + GLOBAL_TOTAL_WIDTH ))
150122
123+
# Count total workflows for progress display
124+
TOTAL_WORKFLOWS=$(echo "$WORKFLOWS" | jq -r '. | length')
125+
151126
# Function to print dynamic table headers padded with '=' and spaces
152127
print_header() {
153128
local name="$1"
@@ -173,48 +148,51 @@ jobs:
173148
"$WORKFLOW_COUNT_WIDTH" "$(printf '%.0s-' $(seq 1 $WORKFLOW_COUNT_WIDTH))" \
174149
"$GLOBAL_TOTAL_WIDTH" "$(printf '%.0s-' $(seq 1 $GLOBAL_TOTAL_WIDTH))"
175150
176-
# Process each workflow by name
177-
for i in "${!WORKFLOW_NAMES_ARRAY[@]}"; do
151+
# Loop over deleted workflows JSON
152+
echo "$WORKFLOWS" | jq -c '.[]' | while read -r wf; do
153+
CURRENT_INDEX=$((CURRENT_INDEX + 1))
154+
WORKFLOW_NAME=$(echo "$wf" | jq -r '.name')
155+
WORKFLOW_ID=$(echo "$wf" | jq -r '.databaseId')
156+
WORKFLOW_PATH=$(echo "$wf" | jq -r '.path')
157+
158+
# Safety checks
159+
if [ -z "$WORKFLOW_NAME" ]; then
160+
echo "::error title=Workflow name empty::Resolved workflow name is empty at index $CURRENT_INDEX"
161+
exit 1
162+
fi
163+
if [ -z "$WORKFLOW_ID" ]; then
164+
echo "::error title=Workflow ID missing::Workflow '$WORKFLOW_NAME' (path: $WORKFLOW_PATH) has no ID"
165+
exit 1
166+
fi
178167
179-
WORKFLOW_NAME=${WORKFLOW_NAMES_ARRAY[$i]}
180-
[ -z "$WORKFLOW_NAME" ] && continue
181-
CURRENT_INDEX=$((i + 1))
182168
WORKFLOW_COUNT=0
183-
184-
WORKFLOW_ID=$(gh workflow list --all --json id,name \
185-
--jq ".[] | select(.name==\"$WORKFLOW_NAME\") | .id")
186-
187-
# GraphQL pagination variables
188169
AFTER_CURSOR=null
189170
171+
# Paginate over workflow runs
190172
while true; do
191173
RESPONSE=$(gh api graphql -F workflowId="$WORKFLOW_ID" -F after="$AFTER_CURSOR" \
192174
-f query='query($workflowId: ID!, $after: String) {
193175
node(id: $workflowId) {
194176
... on Workflow {
195177
runs(first: 100, after: $after) {
196-
pageInfo {
197-
hasNextPage
198-
endCursor
199-
}
200-
nodes {
201-
databaseId
202-
}
178+
pageInfo { hasNextPage endCursor }
179+
nodes { databaseId }
203180
}
204181
}
205182
}
206183
}')
207-
RUN_IDS=$(echo "$RESPONSE" | jq -r '.data.repository.workflowRuns.nodes[].databaseId')
208-
HAS_NEXT=$(echo "$RESPONSE" | jq -r '.data.repository.workflowRuns.pageInfo.hasNextPage')
209-
AFTER_CURSOR=$(echo "$RESPONSE" | jq -r '.data.repository.workflowRuns.pageInfo.endCursor')
184+
185+
RUN_IDS=$(echo "$RESPONSE" | jq -r '.data.node.runs.nodes[].databaseId')
186+
HAS_NEXT=$(echo "$RESPONSE" | jq -r '.data.node.runs.pageInfo.hasNextPage')
187+
AFTER_CURSOR=$(echo "$RESPONSE" | jq -r '.data.node.runs.pageInfo.endCursor')
210188
211189
[ -z "$RUN_IDS" ] && break
212190
213191
BATCH_COUNT=$(echo "$RUN_IDS" | wc -l | tr -d ' ')
214192
WORKFLOW_COUNT=$((WORKFLOW_COUNT + BATCH_COUNT))
215193
TOTAL_AFFECTED=$((TOTAL_AFFECTED + BATCH_COUNT))
216194
217-
# Print progress line
195+
# Print progress
218196
printf "%*s | %-*s | %*s | %*s\n" \
219197
"$INDEX_WIDTH" "[$CURRENT_INDEX/$TOTAL_WORKFLOWS]" \
220198
"$MAX_WF_LENGTH" "$WORKFLOW_NAME" \
@@ -223,30 +201,15 @@ jobs:
223201
224202
if [ "$MODE" = "execute" ]; then
225203
for RUN_ID in $RUN_IDS; do
226-
echo | gh run delete "$RUN_ID" >/dev/null
204+
gh run delete "$RUN_ID" >/dev/null
227205
done
228206
fi
229207
230208
[ "$HAS_NEXT" != "true" ] && break
231209
232-
# TEMPORARY break for testing large workflows
210+
# TEMPORARY safety break
233211
if [ "$WORKFLOW_COUNT" -gt 200 ]; then
234212
echo " ⚠️ Temporary break: workflow count exceeded 200, stopping early."
235213
break
236214
fi
237215
done
238-
239-
SUMMARY+=("$WORKFLOW_NAME|$WORKFLOW_COUNT")
240-
done
241-
242-
# === Summary Header ===
243-
print_header "Workflow Cleanup Summary"
244-
printf "%*s | %-*s | %-*s | %-*s\n" \
245-
"$INDEX_WIDTH" "" \
246-
"$MAX_WF_LENGTH" "Workflow" \
247-
"$WORKFLOW_COUNT_WIDTH" "Runs" \
248-
"$GLOBAL_TOTAL_WIDTH" ""
249-
printf "%*s-+-%-*s-+-%-*s-+-%-*s\n" \
250-
"$INDEX_WIDTH" "$(printf '%.0s-' $(seq 1 $INDEX_WIDTH))" \
251-
"$MAX_WF_LENGTH" "$(printf '%.0s-' $(seq 1 $MAX_WF_LENGTH))" \
252-
"$WORKFLOW_COUNT_WIDT

0 commit comments

Comments
 (0)