Skip to content

Commit f1d943c

Browse files
committed
fix delete
1 parent 9e92045 commit f1d943c

3 files changed

Lines changed: 108 additions & 9 deletions

File tree

.github/scripts/delete_unused_images.sh

Lines changed: 81 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,39 @@
11
#!/usr/bin/env bash
22

33
DRY_RUN=false
4+
DELETE_PR=false
5+
DELETE_CI=false
46

57
while [[ $# -gt 0 ]]; do
68
case "$1" in
79
--dry-run|-n)
810
DRY_RUN=true
911
shift
1012
;;
13+
--delete-pr)
14+
DELETE_PR=true
15+
shift
16+
;;
17+
--delete-ci)
18+
DELETE_CI=true
19+
shift
20+
;;
1121
--help|-h)
12-
echo "Usage: $0 [--dry-run]"
22+
echo "Usage: $0 [--dry-run] [--delete-pr] [--delete-ci]"
1323
exit 0
1424
;;
1525
*)
1626
echo "Unknown option: $1" >&2
17-
echo "Usage: $0 [--dry-run]" >&2
27+
echo "Usage: $0 [--dry-run] [--delete-pr] [--delete-ci]" >&2
1828
exit 1
1929
;;
2030
esac
2131
done
2232

33+
if [[ "${DELETE_PR}" == "false" && "${DELETE_CI}" == "false" ]]; then
34+
DELETE_PR=true
35+
fi
36+
2337
get_container_package_name() {
2438
local container_name=$1
2539

@@ -66,12 +80,12 @@ delete_pr_images() {
6680

6781
while IFS= read -r tag; do
6882
local pull_request
69-
if [[ "${tag}" =~ ^pr-([0-9]+)- ]]; then
83+
if [[ "${tag}" =~ ^pr-([0-9]+)(-.+)?$ ]]; then
7084
pull_request=${BASH_REMATCH[1]}
71-
elif [[ "${tag}" =~ ^githubactions-pr-([0-9]+)- ]]; then
85+
elif [[ "${tag}" =~ ^githubactions-pr-([0-9]+)(-.+)?$ ]]; then
7286
pull_request=${BASH_REMATCH[1]}
7387
else
74-
echo "Tag ${tag} does not match expected PR tag format, skipping."
88+
echo "Tag ${tag} does not match expected PR tag format for container ${container_name}, skipping."
7589
continue
7690
fi
7791

@@ -108,16 +122,75 @@ delete_pr_images() {
108122
done <<<"${tags}"
109123
}
110124

125+
delete_ci_images() {
126+
local container_name=$1
127+
local package_name
128+
local versions_json
129+
local tags
130+
131+
if [[ -z "${container_name}" ]]; then
132+
echo "Container name is required" >&2
133+
return 1
134+
fi
135+
136+
package_name=$(get_container_package_name "${container_name}")
137+
versions_json=$(get_container_versions_json "${container_name}")
138+
tags=$(jq -r '[.[].metadata.container.tags[]?] | unique | .[]' <<<"${versions_json}")
139+
140+
if [[ -z "${tags}" ]]; then
141+
echo "No tags found for container ${container_name}, skipping."
142+
return 0
143+
fi
144+
145+
while IFS= read -r tag; do
146+
if [[ ! "${tag}" =~ ^ci-[0-9a-fA-F]{8}.*$ ]] && [[ ! "${tag}" =~ ^githubactions-ci-[0-9a-fA-F]{8}.*$ ]]; then
147+
echo "Tag ${tag} does not match expected CI tag format for container ${container_name}, skipping."
148+
continue
149+
fi
150+
151+
jq -r --arg tag "${tag}" '.[] | select(.metadata.container.tags[]? == $tag) | .id' \
152+
<<<"${versions_json}" \
153+
| while IFS= read -r version_id; do
154+
if [[ -n "${version_id}" ]]; then
155+
if [[ "${DRY_RUN}" == "true" ]]; then
156+
echo "[DRY RUN] Would delete CI image with tag ${tag} (version ID: ${version_id}) from container ${container_name}."
157+
else
158+
echo "Deleting CI image with tag ${tag} (version ID: ${version_id}) from container ${container_name}..."
159+
gh api \
160+
-H "Accept: application/vnd.github+json" \
161+
-X DELETE \
162+
"/orgs/nhsdigital/packages/container/${package_name}/versions/${version_id}"
163+
fi
164+
fi
165+
done
166+
done <<<"${tags}"
167+
}
168+
111169

112170
language_folders=$(find src/languages -mindepth 1 -maxdepth 1 -type d -printf '%f\n' | jq -R -s -c 'split("\n")[:-1]')
113171
project_folders=$(find src/projects -mindepth 1 -maxdepth 1 -type d -printf '%f\n' | jq -R -s -c 'split("\n")[:-1]')
114172

115173
for container_name in $(jq -r '.[]' <<<"${project_folders}"); do
116-
delete_pr_images "${container_name}"
174+
if [[ "${DELETE_PR}" == "true" ]]; then
175+
delete_pr_images "${container_name}"
176+
fi
177+
if [[ "${DELETE_CI}" == "true" ]]; then
178+
delete_ci_images "${container_name}"
179+
fi
117180
done
118181

119182
for container_name in $(jq -r '.[]' <<<"${language_folders}"); do
120-
delete_pr_images "${container_name}"
183+
if [[ "${DELETE_PR}" == "true" ]]; then
184+
delete_pr_images "${container_name}"
185+
fi
186+
if [[ "${DELETE_CI}" == "true" ]]; then
187+
delete_ci_images "${container_name}"
188+
fi
121189
done
122190

123-
delete_pr_images "base"
191+
if [[ "${DELETE_PR}" == "true" ]]; then
192+
delete_pr_images "base"
193+
fi
194+
if [[ "${DELETE_CI}" == "true" ]]; then
195+
delete_ci_images "base"
196+
fi

.github/workflows/delete_old_images.yml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,13 @@ jobs:
2626

2727
- name: delete unused images
2828
shell: bash
29-
run: .github/scripts/delete_unused_images.sh
29+
run: |
30+
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
31+
.github/scripts/delete_unused_images.sh --delete-pr
32+
elif [[ "${{ github.event_name }}" == "schedule" ]]; then
33+
.github/scripts/delete_unused_images.sh --delete-ci
34+
else
35+
.github/scripts/delete_unused_images.sh
36+
fi
3037
env:
3138
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,25 @@ poetry run python \
274274
--output src/projects/fhir_facade_api/.trivyignore.new.yaml
275275
```
276276

277+
## Cleaning up unused container images
278+
279+
There is a script to delete unused container images. This runs on every merge to main, and deletes pull request images, and on a weekly schedule which deletes images created by ci.
280+
You can run it manually using the following. Using the `dry-run` flag just shows what would be deleted
281+
282+
```
283+
make github-login
284+
bash .github/scripts/delete_unused_images.sh --delete-pr --dry-run
285+
bash .github/scripts/delete_unused_images.sh --delete-ci --dry-run
286+
bash .github/scripts/delete_unused_images.sh --delete-pr --delete-ci
287+
```
288+
289+
Flags:
290+
- `--dry-run` (`-n`) shows what would be deleted without deleting anything.
291+
- `--delete-pr` deletes images tagged with `pr-...` or `githubactions-pr-...` only when the PR is closed.
292+
- `--delete-ci` deletes images tagged with `ci-<8 hex sha>...` or `githubactions-ci-<8 hex sha>...`.
293+
294+
If neither `--delete-pr` nor `--delete-ci` is set, the script defaults to `--delete-pr`.
295+
277296
## Common makefile targets
278297
There are a set of common Makefiles that are defined in `src/base/.devcontainer/Mk` and are included from `common.mk`. These are installed to /usr/local/share/eps/Mk on the base image so are available for all containers.
279298

0 commit comments

Comments
 (0)