Skip to content

Commit 7de6c40

Browse files
committed
ci: add cleanup report and set default retention days
- Set default retention_days to 45 days (previously empty) - Add new step to generate GHCR cleanup report in GitHub Actions summary - Remove unused IMAGES_TO_KEEP variable from SHA-only cleanup step - Add step ID for SHA-only cleanup to reference its output - Simplify loop iteration by removing unused index variable
1 parent b5eab14 commit 7de6c40

File tree

1 file changed

+64
-9
lines changed

1 file changed

+64
-9
lines changed

.github/workflows/cleanup-ghcr-images.yml

Lines changed: 64 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ on:
1212
retention_days:
1313
description: Delete non-SHA-only image versions older than this many days
1414
required: false
15-
default: ''
15+
default: '45'
1616
delete_sha_only_tags:
1717
description: Delete image versions that only have SHA tags
1818
required: false
@@ -175,25 +175,20 @@ jobs:
175175
return JSON.stringify(deletedVersionIds);
176176
177177
- name: Delete container versions that only have SHA tags
178+
id: cleanup_sha_only
178179
if: ${{ env.DELETE_SHA_ONLY_TAGS == 'true' }}
179180
uses: actions/github-script@v8
180181
env:
181182
PACKAGE_NAME: ${{ env.PACKAGE_NAME }}
182-
IMAGES_TO_KEEP: ${{ env.IMAGES_TO_KEEP }}
183183
DRY_RUN: ${{ env.DRY_RUN }}
184184
DELETED_VERSION_IDS: ${{ steps.cleanup_by_age.outputs.result }}
185185
with:
186186
script: |
187187
const owner = context.repo.owner;
188188
const packageType = 'container';
189189
const packageName = process.env.PACKAGE_NAME;
190-
const imagesToKeep = Math.max(1, Number(process.env.IMAGES_TO_KEEP || '4'));
191190
const dryRun = process.env.DRY_RUN === 'true';
192191
193-
if (!Number.isFinite(imagesToKeep)) {
194-
throw new Error(`IMAGES_TO_KEEP must be a number, received: ${process.env.IMAGES_TO_KEEP}`);
195-
}
196-
197192
const paginateVersions = async () => {
198193
try {
199194
return {
@@ -267,7 +262,7 @@ jobs:
267262
return;
268263
}
269264
270-
for (const [index, version] of remainingVersions.entries()) {
265+
for (const version of remainingVersions) {
271266
const tags = version.metadata?.container?.tags ?? [];
272267
const isShaOnly = tags.length > 0 && tags.every(isShaTag);
273268
if (!isShaOnly) {
@@ -279,5 +274,65 @@ jobs:
279274
if (!dryRun) {
280275
await deleteVersion(scope, version.id);
281276
}
282-
retainedCount -= 1;
283277
}
278+
279+
const shaOnlyDeleted = remainingVersions.filter(v => {
280+
const tags = v.metadata?.container?.tags ?? [];
281+
return tags.length > 0 && tags.every(isShaTag);
282+
});
283+
284+
return JSON.stringify({
285+
totalBefore: sortedVersions.length,
286+
ageBasedDeleted: JSON.parse(process.env.DELETED_VERSION_IDS || '[]').length,
287+
shaOnlyDeleted: shaOnlyDeleted.length,
288+
remaining: sortedVersions.length - (dryRun ? JSON.parse(process.env.DELETED_VERSION_IDS || '[]').length + shaOnlyDeleted.length : 0),
289+
});
290+
291+
- name: Generate cleanup report
292+
if: always()
293+
env:
294+
AGE_BASED_RESULT: ${{ steps.cleanup_by_age.outputs.result }}
295+
SHA_ONLY_RESULT: ${{ steps.cleanup_sha_only.outputs.result }}
296+
DELETE_SHA_ONLY_TAGS: ${{ env.DELETE_SHA_ONLY_TAGS }}
297+
DRY_RUN: ${{ env.DRY_RUN }}
298+
IMAGES_TO_KEEP: ${{ env.IMAGES_TO_KEEP }}
299+
RETENTION_DAYS: ${{ env.RETENTION_DAYS }}
300+
run: |
301+
echo "## 🧹 GHCR Cleanup Report" >> $GITHUB_STEP_SUMMARY
302+
echo "" >> $GITHUB_STEP_SUMMARY
303+
304+
if [ "$DRY_RUN" = "true" ]; then
305+
echo "" >> $GITHUB_STEP_SUMMARY
306+
echo "> ⚠️ **Dry run mode** - no images were actually deleted" >> $GITHUB_STEP_SUMMARY
307+
echo "" >> $GITHUB_STEP_SUMMARY
308+
fi
309+
echo "" >> $GITHUB_STEP_SUMMARY
310+
311+
echo "### Configuration" >> $GITHUB_STEP_SUMMARY
312+
echo "| Setting | Value |" >> $GITHUB_STEP_SUMMARY
313+
echo "|---------|-------|" >> $GITHUB_STEP_SUMMARY
314+
echo "| Images to keep | ${IMAGES_TO_KEEP} |" >> $GITHUB_STEP_SUMMARY
315+
echo "| Retention days | ${RETENTION_DAYS} |" >> $GITHUB_STEP_SUMMARY
316+
echo "| Delete SHA-only tags | ${DELETE_SHA_ONLY_TAGS} |" >> $GITHUB_STEP_SUMMARY
317+
echo "" >> $GITHUB_STEP_SUMMARY
318+
319+
if [ -n "$SHA_ONLY_RESULT" ] && [ "$SHA_ONLY_RESULT" != "null" ]; then
320+
AGE_DELETED=$(echo "$AGE_BASED_RESULT" | jq -r 'if type == "array" then length elif type == "object" then .ageBasedDeleted // 0 else 0 end')
321+
SHA_DELETED=$(echo "$SHA_ONLY_RESULT" | jq -r '.shaOnlyDeleted // 0')
322+
TOTAL_BEFORE=$(echo "$SHA_ONLY_RESULT" | jq -r '.totalBefore // 0')
323+
REMAINING=$(echo "$SHA_ONLY_RESULT" | jq -r '.remaining // 0')
324+
325+
echo "### Summary" >> $GITHUB_STEP_SUMMARY
326+
echo "| Metric | Count |" >> $GITHUB_STEP_SUMMARY
327+
echo "|--------|-------|" >> $GITHUB_STEP_SUMMARY
328+
echo "| Total versions before | ${TOTAL_BEFORE} |" >> $GITHUB_STEP_SUMMARY
329+
echo "| Age-based deletions | ${AGE_DELETED} |" >> $GITHUB_STEP_SUMMARY
330+
echo "| SHA-only deletions | ${SHA_DELETED} |" >> $GITHUB_STEP_SUMMARY
331+
echo "| **Remaining versions** | **${REMAINING}** |" >> $GITHUB_STEP_SUMMARY
332+
elif [ -n "$AGE_BASED_RESULT" ] && [ "$AGE_BASED_RESULT" != "null" ]; then
333+
AGE_DELETED=$(echo "$AGE_BASED_RESULT" | jq -r 'if type == "array" then length else 0 end')
334+
echo "### Summary" >> $GITHUB_STEP_SUMMARY
335+
echo "| Metric | Count |" >> $GITHUB_STEP_SUMMARY
336+
echo "|--------|-------|" >> $GITHUB_STEP_SUMMARY
337+
echo "| Age-based deletions | ${AGE_DELETED} |" >> $GITHUB_STEP_SUMMARY
338+
fi

0 commit comments

Comments
 (0)