diff --git a/README.md b/README.md
index 6d6f76fb..ecef237a 100644
--- a/README.md
+++ b/README.md
@@ -66,6 +66,11 @@ This action deletes versions of a package from [GitHub Packages](https://github.
# Cannot be used with `num-old-versions-to-delete`.
delete-only-untagged-versions:
+ # If true it will also ignore tags matching the regex provided in `ignore-versions`
+ # Defaults to false.
+ # Can only be used with `ignore-versions`.
+ ignore-versions-include-tags:
+
# The token used to authenticate with GitHub Packages.
# Defaults to github.token.
# Required if the repo running the workflow does not have access to delete the package.
@@ -89,6 +94,8 @@ This action deletes versions of a package from [GitHub Packages](https://github.
- `min-versions-to-keep` + `delete-only-pre-release-versions`
- `delete-only-untagged-versions`
- `min-versions-to-keep` + `delete-only-untagged-versions`
+ - `ignore-versions-include-tags` + `ignore-versions`
+ - `ignore-versions-include-tags` + `ignore-versions` + `min-versions-to-keep`
# Scenarios
@@ -106,6 +113,8 @@ This action deletes versions of a package from [GitHub Packages](https://github.
- [Delete oldest version of a package](#delete-oldest-version-of-a-package)
- [Delete a specific version of a package](#delete-a-specific-version-of-a-package)
- [Delete multiple specific versions of a package](#delete-multiple-specific-versions-of-a-package)
+ - [Delete all white ignoring particular tags](#delete-all-while-ignoring-particular-tags)
+ - [Delete all except y latest versions while ignoring particular tags](#delete-all-except-y-latest-versions-while-ignoring-particular-tags)
- [License](#license)
@@ -405,6 +414,44 @@ This action deletes versions of a package from [GitHub Packages](https://github.
token: ${{ secrets.PAT }}
```
+
+
+ ### Delete all while ignoring particular tags
+
+ To delete all while ignoring particular tags, the __package-name__, __ignore-versions-include-tags__ and __ignore-versions__ inputs are required.
+
+ __Example__
+
+ Deletes all versions of a package excluding package containing the `important-tag` tag.
+
+ ```yaml
+ - uses: actions/delete-package-version@v4
+ with:
+ package-name: 'test-package'
+ package-type: 'container'
+ ignore-versions: '^important-tag$'
+ ignore-versions-include-tags: 'true'
+ token: ${{ secrets.PAT }}
+ ```
+
+ ### Delete all except y latest versions while ignoring particular tags
+
+ To delete all except y latest versions while ignoring particular tags, the __package-name__, __min-versions-to-keep__, __ignore-versions-include-tags__ and __ignore-versions__ inputs are required.
+
+ __Example__
+
+ Delete all except latest 3 package versions excluding package containing the `important-tag` tag.
+
+ ```yaml
+ - uses: actions/delete-package-versions@v4
+ with:
+ package-name: 'test-package'
+ package-type: 'container'
+ min-versions-to-keep: 3
+ ignore-versions: '^important-tag$'
+ ignore-versions-include-tags: 'true'
+ ```
+
# License
The scripts and documentation in this project are released under the [MIT License](https://github.com/actions/delete-package-versions/blob/main/LICENSE)
diff --git a/__tests__/delete.test.ts b/__tests__/delete.test.ts
index 96dda11a..d9ca0133 100644
--- a/__tests__/delete.test.ts
+++ b/__tests__/delete.test.ts
@@ -341,6 +341,90 @@ describe('index tests -- call rest', () => {
)
})
+ it('finalIds test - no versions deleted if tags match ignore version and include tags is enabled', done => {
+ const numVersions = 10
+ let apiCalled = 0
+
+ const versions = getMockedVersionsResponse(
+ numVersions,
+ 0,
+ 'container',
+ true
+ )
+
+ server.use(
+ rest.get(
+ 'https://api.github.com/users/test-owner/packages/container/test-package/versions',
+ (req, res, ctx) => {
+ apiCalled++
+ return res(ctx.status(200), ctx.json(versions))
+ }
+ )
+ )
+
+ finalIds(
+ getInput({
+ minVersionsToKeep: 2,
+ packageType: 'container',
+ ignoreVersions: RegExp('^(latest[1-3]{1})$'),
+ includeTags: 'true'
+ })
+ ).subscribe(ids => {
+ expect(apiCalled).toBe(1)
+ expect(ids).toStrictEqual(['4', '5', '6', '7', '8'])
+ done()
+ })
+ })
+
+ it('', done => {
+ const numVersions = 10
+ let apiCalled = 0
+
+ let date = new Date()
+ date.setUTCFullYear(2000, 1, 1)
+
+ const version = {
+ id: 1,
+ name: '1.0.0',
+ url: '',
+ created_at: date.toUTCString(),
+ package_html_url: '',
+ updated_at: '',
+ metadata: {
+ package_type: 'container',
+ container: {
+ tags: [
+ 'test',
+ '9970186500fd471320e7340b256229209899bde5',
+ 'my-first-pr'
+ ] as string[]
+ }
+ }
+ }
+
+ server.use(
+ rest.get(
+ 'https://api.github.com/users/test-owner/packages/container/test-package/versions',
+ (req, res, ctx) => {
+ apiCalled++
+ return res(ctx.status(200), ctx.json([version]))
+ }
+ )
+ )
+
+ finalIds(
+ getInput({
+ packageType: 'container',
+ ignoreVersions: RegExp('^production|acceptance|test$'),
+ includeTags: 'true'
+ })
+ ).subscribe(ids => {
+ expect(apiCalled).toBe(1)
+ expect(ids.length).toBe(0)
+ done()
+ })
+ })
+
it('deleteVersions test - missing token', done => {
deleteVersions(getInput({token: ''})).subscribe({
error: err => {
@@ -477,7 +561,8 @@ const defaultInput: InputParams = {
numOldVersionsToDelete: RATE_LIMIT,
minVersionsToKeep: -1,
ignoreVersions: RegExp('^$'),
- token: 'test-token'
+ token: 'test-token',
+ includeTags: 'false'
}
function getInput(params?: InputParams): Input {
diff --git a/__tests__/version/get-version.test.ts b/__tests__/version/get-version.test.ts
index 313a93dc..8df47eec 100644
--- a/__tests__/version/get-version.test.ts
+++ b/__tests__/version/get-version.test.ts
@@ -114,8 +114,10 @@ describe('get versions tests -- mock rest', () => {
expect(result.versions[i].created_at).toBe(resp[i].created_at)
if (i < numTaggedVersions) {
expect(result.versions[i].tagged).toBe(true)
+ expect(result.versions[i].tags.length).toBe(1)
} else {
expect(result.versions[i].tagged).toBe(false)
+ expect(result.versions[i].tags.length).toBe(0)
}
}
expect(result.paginate).toBe(true)
diff --git a/action.yml b/action.yml
index 789a96e9..fd6e0834 100644
--- a/action.yml
+++ b/action.yml
@@ -64,6 +64,13 @@ inputs:
required: false
default: "false"
+ ignore-versions-include-tags:
+ description: >
+ Next to the version also ignore tags matching the ignore-versions regex.
+ By default this is set to false
+ required: false
+ default: "false"
+
token:
description: >
Token with the necessary scopes to delete package versions.
diff --git a/dist/index.js b/dist/index.js
index a2729f70..5bc91720 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -41,6 +41,10 @@ function finalIds(input) {
Then compute number of versions to delete (toDelete) based on the inputs.
*/
value = value.filter(info => !input.ignoreVersions.test(info.version));
+ // Filter out tags that are to be ignored only when including tags is enabled
+ if (input.includeTags === 'true') {
+ value = value.filter(info => !info.tags.some(tag => input.ignoreVersions.test(tag)));
+ }
if (input.deleteUntaggedVersions === 'true') {
value = value.filter(info => !info.tagged);
}
@@ -95,7 +99,8 @@ const defaultParams = {
ignoreVersions: new RegExp(''),
deletePreReleaseVersions: '',
token: '',
- deleteUntaggedVersions: ''
+ deleteUntaggedVersions: '',
+ includeTags: ''
};
class Input {
constructor(params) {
@@ -111,6 +116,7 @@ class Input {
this.token = validatedParams.token;
this.numDeleted = 0;
this.deleteUntaggedVersions = validatedParams.deleteUntaggedVersions;
+ this.includeTags = validatedParams.includeTags;
}
hasOldestVersionQueryInfo() {
return !!(this.owner &&
@@ -231,17 +237,18 @@ function getOldestVersions(owner, packageName, packageType, numVersions, page, t
}), (0, operators_1.map)(response => {
const resp = {
versions: response.data.map((version) => {
- let tagged = false;
+ let tags = [];
if (package_type === 'container' &&
version.metadata &&
version.metadata.container) {
- tagged = version.metadata.container.tags.length > 0;
+ tags = version.metadata.container.tags;
}
return {
id: version.id,
version: version.name,
created_at: version.created_at,
- tagged
+ tagged: tags.length > 0,
+ tags
};
}),
page,
@@ -43941,7 +43948,8 @@ function getActionInput() {
ignoreVersions: RegExp((0, core_1.getInput)('ignore-versions')),
deletePreReleaseVersions: (0, core_1.getInput)('delete-only-pre-release-versions').toLowerCase(),
token: (0, core_1.getInput)('token'),
- deleteUntaggedVersions: (0, core_1.getInput)('delete-only-untagged-versions').toLowerCase()
+ deleteUntaggedVersions: (0, core_1.getInput)('delete-only-untagged-versions').toLowerCase(),
+ includeTags: (0, core_1.getInput)('ignore-versions-include-tags').toLowerCase()
});
}
function run() {
diff --git a/src/delete.ts b/src/delete.ts
index 4eb953fe..37c9e334 100644
--- a/src/delete.ts
+++ b/src/delete.ts
@@ -76,6 +76,13 @@ export function finalIds(input: Input): Observable {
*/
value = value.filter(info => !input.ignoreVersions.test(info.version))
+ // Filter out tags that are to be ignored only when including tags is enabled
+ if (input.includeTags === 'true') {
+ value = value.filter(
+ info => !info.tags.some(tag => input.ignoreVersions.test(tag))
+ )
+ }
+
if (input.deleteUntaggedVersions === 'true') {
value = value.filter(info => !info.tagged)
}
diff --git a/src/input.ts b/src/input.ts
index d05e0690..ef671d48 100644
--- a/src/input.ts
+++ b/src/input.ts
@@ -9,6 +9,7 @@ export interface InputParams {
token?: string
deletePreReleaseVersions?: string
deleteUntaggedVersions?: string
+ includeTags?: string
}
const defaultParams = {
@@ -21,7 +22,8 @@ const defaultParams = {
ignoreVersions: new RegExp(''),
deletePreReleaseVersions: '',
token: '',
- deleteUntaggedVersions: ''
+ deleteUntaggedVersions: '',
+ includeTags: ''
}
export class Input {
@@ -36,6 +38,7 @@ export class Input {
token: string
numDeleted: number
deleteUntaggedVersions: string
+ includeTags: string
constructor(params?: InputParams) {
const validatedParams: Required = {...defaultParams, ...params}
@@ -51,6 +54,7 @@ export class Input {
this.token = validatedParams.token
this.numDeleted = 0
this.deleteUntaggedVersions = validatedParams.deleteUntaggedVersions
+ this.includeTags = validatedParams.includeTags
}
hasOldestVersionQueryInfo(): boolean {
@@ -65,6 +69,7 @@ export class Input {
checkInput(): boolean {
if (this.packageType.toLowerCase() !== 'container') {
this.deleteUntaggedVersions = 'false'
+ this.includeTags = 'false'
}
if (
diff --git a/src/main.ts b/src/main.ts
index 2e3df1b2..d948dd01 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -22,7 +22,8 @@ function getActionInput(): Input {
token: getInput('token'),
deleteUntaggedVersions: getInput(
'delete-only-untagged-versions'
- ).toLowerCase()
+ ).toLowerCase(),
+ includeTags: getInput('ignore-versions-include-tags').toLowerCase()
})
}
diff --git a/src/version/get-versions.ts b/src/version/get-versions.ts
index 342cad2b..5ee97f51 100644
--- a/src/version/get-versions.ts
+++ b/src/version/get-versions.ts
@@ -9,6 +9,7 @@ export interface RestVersionInfo {
version: string
created_at: string
tagged: boolean
+ tags: string[]
}
export interface RestQueryInfo {
@@ -57,20 +58,22 @@ export function getOldestVersions(
map(response => {
const resp = {
versions: response.data.map((version: GetVersionsResponse[0]) => {
- let tagged = false
+ let tags: string[] = []
+
if (
package_type === 'container' &&
version.metadata &&
version.metadata.container
) {
- tagged = version.metadata.container.tags.length > 0
+ tags = version.metadata.container.tags
}
return {
id: version.id,
version: version.name,
created_at: version.created_at,
- tagged
+ tagged: tags.length > 0,
+ tags
}
}),
page,