Skip to content

Commit d32e73a

Browse files
Copilotneilime
andcommitted
feat: add clean-images action wrapper
Co-authored-by: neilime <314088+neilime@users.noreply.github.com> Signed-off-by: Emilien Escalle <emilien.escalle@escemi.com>
1 parent 82858e2 commit d32e73a

9 files changed

Lines changed: 297 additions & 113 deletions

File tree

.github/workflows/__test-action-docker-prune-pull-requests-image-tags.yml

Lines changed: 11 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -175,32 +175,16 @@ jobs:
175175
steps:
176176
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
177177

178-
- id: get-issue-number
179-
if: ${{ github.event_name == 'pull_request' }}
180-
uses: hoverkraft-tech/ci-github-common/actions/get-issue-number@b7dd413209df265bef8d7eb0efb117eaabc684c4 # 0.27.0
181-
182-
- name: Delete test packages
183-
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
178+
- name: Delete test package
179+
uses: ./actions/docker/clean-images
180+
continue-on-error: true
184181
with:
185-
github-token: ${{ github.token }}
186-
script: |
187-
const packagesToDelete = ["${{ env.IMAGE }}", "${{ env.IMAGE }}/cache"];
188-
189-
for (const packageName of packagesToDelete) {
190-
const packagePayload = {
191-
package_type: 'container',
192-
package_name: `ci-github-container/${packageName}`,
193-
org: 'hoverkraft-tech',
194-
};
195-
196-
try {
197-
await github.rest.packages.deletePackageForOrg(packagePayload);
198-
} catch (error) {
199-
if (error.status === 404) {
200-
core.warning(`Package "${packagePayload.package_name}" not found.`);
201-
} else {
202-
throw error;
203-
}
204-
}
182+
package: ci-github-container/${{ env.IMAGE }}
183+
tags: "*"
205184

206-
}
185+
- name: Delete test cache package
186+
uses: ./actions/docker/clean-images
187+
continue-on-error: true
188+
with:
189+
package: ci-github-container/${{ env.IMAGE }}/cache
190+
tags: "*"

.github/workflows/__test-workflow-docker-build-images-platforms-and-signing.yml

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -274,16 +274,15 @@ jobs:
274274
strategy:
275275
fail-fast: false
276276
matrix: ${{ fromJson(needs.arrange.outputs.matrix) }}
277+
permissions:
278+
packages: write
277279
steps:
278-
- name: Delete ephemeral test packages
279-
env:
280-
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
281-
IMAGE_NAME: ${{ matrix.image-name }}
282-
run: |
283-
gh api \
284-
--method DELETE \
285-
-H "Accept: application/vnd.github+json" \
286-
-H "X-GitHub-Api-Version: 2022-11-28" \
287-
/orgs/${{ github.repository_owner }}/packages/container/ci-github-container%2F"${IMAGE_NAME}" || echo "No ${IMAGE_NAME} package to delete"
280+
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
288281

282+
- name: Delete ephemeral test packages
283+
uses: ./actions/docker/clean-images
284+
continue-on-error: true
285+
with:
286+
package: ci-github-container/${{ matrix.image-name }}
287+
tags: "*"
289288
# jscpd:ignore-end

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ _Actions that operate on OCI images across their build, metadata, and lifecycle
2424

2525
#### - [Build image](actions/docker/build-image/README.md)
2626

27+
#### - [Clean images](actions/docker/clean-images/README.md)
28+
2729
#### - [Create images manifests](actions/docker/create-images-manifests/README.md)
2830

2931
#### - [Get image metadata](actions/docker/get-image-metadata/README.md)
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
<!-- header:start -->
2+
3+
# ![Icon](data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJmZWF0aGVyIGZlYXRoZXItdHJhc2gtMiIgY29sb3I9ImJsdWUiPjxwb2x5bGluZSBwb2ludHM9IjMgNiA1IDYgMjEgNiI+PC9wb2x5bGluZT48cGF0aCBkPSJNMTkgNnYxNGEyIDIgMCAwIDEtMiAySDdhMiAyIDAgMCAxLTItMlY2bTMgMFY0YTIgMiAwIDAgMSAyLTJoNGEyIDIgMCAwIDEgMiAydjIiPjwvcGF0aD48bGluZSB4MT0iMTAiIHkxPSIxMSIgeDI9IjEwIiB5Mj0iMTciPjwvbGluZT48bGluZSB4MT0iMTQiIHkxPSIxMSIgeDI9IjE0IiB5Mj0iMTciPjwvbGluZT48L3N2Zz4=) GitHub Action: Docker - Clean images
4+
5+
<div align="center">
6+
<img src="../../../.github/logo.svg" width="60px" align="center" alt="Docker - Clean images" />
7+
</div>
8+
9+
---
10+
11+
<!-- header:end -->
12+
13+
<!-- badges:start -->
14+
15+
[![Marketplace](https://img.shields.io/badge/Marketplace-docker------clean--images-blue?logo=github-actions)](https://github.com/marketplace/actions/docker---clean-images)
16+
[![Release](https://img.shields.io/github/v/release/hoverkraft-tech/ci-github-container)](https://github.com/hoverkraft-tech/ci-github-container/releases)
17+
[![License](https://img.shields.io/github/license/hoverkraft-tech/ci-github-container)](http://choosealicense.com/licenses/mit/)
18+
[![Stars](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-container?style=social)](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-container?style=social)
19+
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/hoverkraft-tech/ci-github-container/blob/main/CONTRIBUTING.md)
20+
21+
<!-- badges:end -->
22+
23+
<!-- overview:start -->
24+
25+
## Overview
26+
27+
Action to clean up container images from GitHub Container Registry (ghcr.io).
28+
This is a wrapper around the ghcr-cleanup-action that provides a consistent interface
29+
for image cleanup operations including deleting untagged images, pruning old tags,
30+
and managing image lifecycle.
31+
32+
<!-- overview:end -->
33+
34+
## Permissions
35+
36+
Set permissions to write packages. This is required to delete images.
37+
38+
```yaml
39+
permissions:
40+
packages: write
41+
```
42+
43+
<!-- usage:start -->
44+
45+
## Usage
46+
47+
```yaml
48+
- uses: hoverkraft-tech/ci-github-container/actions/docker/clean-images@d463aac271c4bec41457c7544d31a75753586145 # copilot/refactor-cleanup-action-architecture
49+
with:
50+
# GitHub token with packages:write and packages:delete permissions.
51+
# See https://docs.github.com/en/packages/learn-github-packages/about-permissions-for-github-packages#about-scopes-and-permissions-for-package-registries.
52+
#
53+
# Default: `${{ github.token }}`
54+
token: ${{ github.token }}
55+
56+
# Comma-separated list of packages to cleanup.
57+
# Example: "application-1,application-2"
58+
#
59+
# This input is required.
60+
package: ""
61+
62+
# Comma-separated list of tags to delete (supports wildcard syntax).
63+
# Example: `pr-*,dev`
64+
#
65+
# This input is required.
66+
tags: ""
67+
```
68+
69+
<!-- usage:end -->
70+
71+
<!-- inputs:start -->
72+
73+
## Inputs
74+
75+
| **Input** | **Description** | **Required** | **Default** |
76+
| ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ | ----------------------- |
77+
| **`token`** | GitHub token with packages:write and packages:delete permissions. | **false** | `$\{\{ github.token }}` |
78+
| | See <https://docs.github.com/en/packages/learn-github-packages/about-permissions-for-github-packages#about-scopes-and-permissions-for-package-registries>. | | |
79+
| **`package`** | Comma-separated list of packages to cleanup. | **true** | - |
80+
| | Example: "application-1,application-2" | | |
81+
| **`tags`** | Comma-separated list of tags to delete (supports wildcard syntax). | **true** | - |
82+
| | Example: `pr-*,dev` | | |
83+
84+
<!-- inputs:end -->
85+
86+
<!-- secrets:start -->
87+
<!-- secrets:end -->
88+
89+
<!-- outputs:start -->
90+
91+
## Outputs
92+
93+
| **Output** | **Description** |
94+
| ------------------------------ | --------------------------------------- |
95+
| **`deleted-package-ids`** | The package IDs that were deleted. |
96+
| **`deleted-package-versions`** | The package versions that were deleted. |
97+
98+
<!-- outputs:end -->
99+
100+
<!-- examples:start -->
101+
102+
## Examples
103+
104+
### Clean up pull request images
105+
106+
Delete images tagged with a pull request pattern after the PR is closed:
107+
108+
```yaml
109+
name: Clean PR Images
110+
on:
111+
pull_request:
112+
types: [closed]
113+
114+
jobs:
115+
cleanup:
116+
runs-on: ubuntu-latest
117+
permissions:
118+
packages: write
119+
steps:
120+
- uses: hoverkraft-tech/ci-github-container/actions/docker/clean-images@d463aac271c4bec41457c7544d31a75753586145 # copilot/refactor-cleanup-action-architecture
121+
with:
122+
package: my-app
123+
delete-tags: pr-${{ github.event.pull_request.number }}-*
124+
```
125+
126+
### Clean up untagged images
127+
128+
Remove all untagged images to save storage:
129+
130+
```yaml
131+
name: Clean Untagged Images
132+
on:
133+
schedule:
134+
- cron: "0 3 * * *" # Daily at 3 AM
135+
136+
jobs:
137+
cleanup:
138+
runs-on: ubuntu-latest
139+
permissions:
140+
packages: write
141+
steps:
142+
- uses: hoverkraft-tech/ci-github-container/actions/docker/clean-images@d463aac271c4bec41457c7544d31a75753586145 # copilot/refactor-cleanup-action-architecture
143+
with:
144+
package: my-app
145+
delete-untagged: true
146+
```
147+
148+
<!-- examples:end -->
149+
150+
<!--
151+
// jscpd:ignore-start
152+
-->
153+
154+
<!-- contributing:start -->
155+
156+
## Contributing
157+
158+
Contributions are welcome! Please see the [contributing guidelines](https://github.com/hoverkraft-tech/ci-github-container/blob/main/CONTRIBUTING.md) for more details.
159+
160+
<!-- contributing:end -->
161+
162+
<!-- security:start -->
163+
<!-- security:end -->
164+
165+
<!-- license:start -->
166+
167+
## License
168+
169+
This project is licensed under the MIT License.
170+
171+
SPDX-License-Identifier: MIT
172+
173+
Copyright © 2025 hoverkraft
174+
175+
For more details, see the [license](http://choosealicense.com/licenses/mit/).
176+
177+
<!-- license:end -->
178+
179+
<!-- generated:start -->
180+
181+
---
182+
183+
This documentation was automatically generated by [CI Dokumentor](https://github.com/hoverkraft-tech/ci-dokumentor).
184+
185+
<!-- generated:end -->
186+
187+
<!--
188+
// jscpd:ignore-end
189+
-->
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
---
2+
name: "Docker - Clean images"
3+
description: |
4+
Action to clean up container images from GitHub Container Registry (ghcr.io).
5+
This is a wrapper around the ghcr-cleanup-action that provides a consistent interface
6+
for image cleanup operations including deleting untagged images, pruning old tags,
7+
and managing image lifecycle.
8+
author: hoverkraft
9+
branding:
10+
icon: trash-2
11+
color: blue
12+
13+
inputs:
14+
token:
15+
description: |
16+
GitHub token with packages:write and packages:delete permissions.
17+
See https://docs.github.com/en/packages/learn-github-packages/about-permissions-for-github-packages#about-scopes-and-permissions-for-package-registries.
18+
default: ${{ github.token }}
19+
required: false
20+
package:
21+
description: |
22+
Comma-separated list of packages to cleanup.
23+
Example: "application-1,application-2"
24+
required: true
25+
tags:
26+
description: |
27+
Comma-separated list of tags to delete (supports wildcard syntax).
28+
Example: `pr-*,dev`
29+
required: true
30+
31+
outputs:
32+
deleted-package-ids:
33+
description: |
34+
The package IDs that were deleted.
35+
value: ${{ steps.cleanup.outputs.deleted-package-ids }}
36+
deleted-package-versions:
37+
description: |
38+
The package versions that were deleted.
39+
value: ${{ steps.cleanup.outputs.deleted-package-versions }}
40+
41+
runs:
42+
using: "composite"
43+
steps:
44+
- id: cleanup
45+
uses: dataaxiom/ghcr-cleanup-action@cd0cdb900b5dbf3a6f2cc869f0dbb0b8211f50c4 # v1.0.16
46+
with:
47+
token: ${{ inputs.token }}
48+
package: ${{ inputs.package }}
49+
tags: ${{ inputs.tags }}
50+
dry-run: ${{ inputs.dry-run }}
51+
delete-ghost-images: ${{ inputs.delete-ghost-images }}
52+
delete-orphaned-images: ${{ inputs.delete-orphaned-images }}
53+
validate: true

actions/docker/prune-pull-requests-image-tags/action.yml

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ outputs:
1414
```json
1515
["1.0.0", "1.0.1"]
1616
```
17-
value: ${{ steps.delete-image-tags.outputs.deleted-image-tags }}
17+
value: ${{ steps.clean-images.outputs.deleted-package-versions }}
1818

1919
inputs:
2020
image:
@@ -41,15 +41,10 @@ runs:
4141
with:
4242
image: ${{ inputs.image }}
4343

44-
- shell: bash
45-
# FIXME: workaround until will be merged: https://github.com/actions/runner/pull/1684
46-
run: |
47-
rm -fr ./self-actions
48-
4944
- id: is-organization-or-user
5045
uses: hoverkraft-tech/ci-github-common/actions/repository-owner-is-organization@b7dd413209df265bef8d7eb0efb117eaabc684c4 # 0.27.0
5146

52-
- id: delete-image-tags
47+
- id: get-tags-to-delete
5348
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
5449
with:
5550
github-token: ${{ inputs.github-token }}
@@ -80,7 +75,7 @@ runs:
8075
const isOrganization = `${{ steps.is-organization-or-user.outputs.is-organization }}` === 'true';
8176
8277
const script = require(`${{ github.action_path }}/index.js`)
83-
const deletedTags = await script({
78+
const tagsToDelete = await script({
8479
github,
8580
context,
8681
core,
@@ -89,4 +84,20 @@ runs:
8984
isOrganization,
9085
});
9186
92-
core.setOutput('deleted-image-tags', JSON.stringify(deletedTags));
87+
// Convert tags to comma-separated string for delete-tags input
88+
const tagsString = tagsToDelete.join(',');
89+
core.setOutput('tags-to-delete', tagsString);
90+
core.info(`Tags to delete: ${tagsString}`);
91+
92+
- id: clean-images
93+
uses: ./self-actions/docker/clean-images
94+
if: steps.get-tags-to-delete.outputs.tags-to-delete != ''
95+
with:
96+
token: ${{ inputs.github-token }}
97+
package: ${{ steps.image-name.outputs.image-name }}
98+
tags: ${{ steps.get-tags-to-delete.outputs.tags-to-delete }}
99+
100+
- shell: bash
101+
# FIXME: workaround until will be merged: https://github.com/actions/runner/pull/1684
102+
run: |
103+
rm -fr ./self-actions

0 commit comments

Comments
 (0)