Skip to content

Commit

Permalink
Added ability to ignore tags when deleting packages
Browse files Browse the repository at this point in the history
  • Loading branch information
Hayena committed Apr 18, 2023
1 parent 9970186 commit bf25fb8
Show file tree
Hide file tree
Showing 9 changed files with 176 additions and 11 deletions.
47 changes: 47 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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

Expand All @@ -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)


Expand Down Expand Up @@ -405,6 +414,44 @@ This action deletes versions of a package from [GitHub Packages](https://github.
token: ${{ secrets.PAT }}
```

<br>

### 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)
Expand Down
87 changes: 86 additions & 1 deletion __tests__/delete.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 => {
Expand Down Expand Up @@ -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 {
Expand Down
2 changes: 2 additions & 0 deletions __tests__/version/get-version.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
7 changes: 7 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
18 changes: 13 additions & 5 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -95,7 +99,8 @@ const defaultParams = {
ignoreVersions: new RegExp(''),
deletePreReleaseVersions: '',
token: '',
deleteUntaggedVersions: ''
deleteUntaggedVersions: '',
includeTags: ''
};
class Input {
constructor(params) {
Expand All @@ -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 &&
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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() {
Expand Down
7 changes: 7 additions & 0 deletions src/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@ export function finalIds(input: Input): Observable<string[]> {
*/
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)
}
Expand Down
7 changes: 6 additions & 1 deletion src/input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export interface InputParams {
token?: string
deletePreReleaseVersions?: string
deleteUntaggedVersions?: string
includeTags?: string
}

const defaultParams = {
Expand All @@ -21,7 +22,8 @@ const defaultParams = {
ignoreVersions: new RegExp(''),
deletePreReleaseVersions: '',
token: '',
deleteUntaggedVersions: ''
deleteUntaggedVersions: '',
includeTags: ''
}

export class Input {
Expand All @@ -36,6 +38,7 @@ export class Input {
token: string
numDeleted: number
deleteUntaggedVersions: string
includeTags: string

constructor(params?: InputParams) {
const validatedParams: Required<InputParams> = {...defaultParams, ...params}
Expand All @@ -51,6 +54,7 @@ export class Input {
this.token = validatedParams.token
this.numDeleted = 0
this.deleteUntaggedVersions = validatedParams.deleteUntaggedVersions
this.includeTags = validatedParams.includeTags
}

hasOldestVersionQueryInfo(): boolean {
Expand All @@ -65,6 +69,7 @@ export class Input {
checkInput(): boolean {
if (this.packageType.toLowerCase() !== 'container') {
this.deleteUntaggedVersions = 'false'
this.includeTags = 'false'
}

if (
Expand Down
3 changes: 2 additions & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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()
})
}

Expand Down
9 changes: 6 additions & 3 deletions src/version/get-versions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export interface RestVersionInfo {
version: string
created_at: string
tagged: boolean
tags: string[]
}

export interface RestQueryInfo {
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit bf25fb8

Please sign in to comment.