Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ This action deletes versions of a package from [GitHub Packages](https://github.
* Delete multiple versions
* Delete specific version(s)
* Delete oldest version(s)
* Delete oldest version(s) while ignoring a specific version pattern
* Delete version(s) of a package that is hosted in the same repo that is executing the workflow
* Delete version(s) of a package that is hosted in a different repo than the one executing the workflow

Expand All @@ -19,7 +20,13 @@ This action deletes versions of a package from [GitHub Packages](https://github.
# Can be a single package version id, or a comma separated list of package version ids.
# Defaults to an empty string.
package-version-ids:


# Regular expression string matching package version names to never delete.
# This has no effect when explicitly specifying package version ids using package-version-ids.
# As a result of the match, less than num-old-versions-to-delete may be deleted.
# Defaults to allowing all packages.
ignored-version-names:

# Owner of the repo hosting the package.
# Defaults to the owner of the repo executing the workflow.
# Required if deleting a version from a package hosted in a different repo than the one executing the workflow.
Expand Down Expand Up @@ -56,6 +63,7 @@ This action deletes versions of a package from [GitHub Packages](https://github.
* [Delete oldest version of a package hosted in the same repo as the workflow](#delete-oldest-version-of-a-package-hosted-in-the-same-repo-as-the-workflow)
* [Delete oldest x number of versions of a package hosted in the same repo as the workflow](#delete-oldest-x-number-of-versions-of-a-package-hosted-in-the-same-repo-as-the-workflow)
* [Delete oldest x number of versions of a package hosted in a different repo than the workflow](#delete-oldest-x-number-of-versions-of-a-package-hosted-in-a-different-repo-than-the-workflow)
* [Delete oldest x number of versions of a package excluding packages whose name matches a given pattern](#delete-oldest-x-number-of-versions-of-a-package-excluding-packages-whose-name-matches-a-given-pattern)

### Delete a specific version of a package hosted in the same repo as the workflow

Expand Down Expand Up @@ -197,6 +205,18 @@ Delete the oldest 3 version of a package hosted in a different repo than the one
token: ${{ secrets.GITHUB_PAT }}
```

### Delete oldest x number of versions of a package excluding packages whose name matches a given pattern

To delete the oldest x nubmer of versions of a package, but exclude packages whost name matches a given pattern from being deleted.

```yaml
- uses: actions/delete-package-versions@v1
with:
package-name: 'test-package'
num-old-versions-to-delete: 3
ignored-version-names: "docker-base-layer|^\\d+\\.\\d+$"
```

# License

The scripts and documentation in this project are released under the [MIT License](https://github.com/actions/delete-package-versions/blob/master/LICENSE)
Expand Down
8 changes: 8 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ inputs:
description: Comma separated string of package version ids to delete.
required: false

ignored-version-names:
description: >
Regular expression string matching package version names to never delete.
This has no effect when explicitly specifying package version ids using package-version-ids.
As a result of the match, less than num-old-versions-to-delete may be deleted.
required: false
default: "^(?!.*)$"

owner:
description: >
Owner of the repo containing the package version to delete.
Expand Down
8 changes: 7 additions & 1 deletion src/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@ export function getVersionIds(input: Input): Observable<string[]> {
input.packageName,
input.numOldVersionsToDelete,
input.token
).pipe(map(versionInfo => versionInfo.map(info => info.id)))
).pipe(
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Hsn723 did you look into a solution that exclude the versions from the query in the first place? If that is even possible.

Could you run into a situation where there'll never be any versions left. The case where numOldVersionsToDelete is smaller than the number of versions matching you regular expression? Would one have to "know your versions" and set this value higher to avoid that or what do you think?

Kind of related: Do you know if this action could remove all versions or will it at least leave one?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did look into passing the filter into the query however the current GitHub GraphQL API v4 does not support any filtering at this time.

Could you run into a situation where there'll never be any versions left.

Indeed, there's the possibility of the oldest numOldVersionsToDelete versions all match the filtering pattern and therefore ending up with nothing to delete. Unfortunately I don't have an elegant solution other than "know your versions" as you mentioned. Or, having a versioning scheme that allows some predictability. Automatically counting up is also an option, however that will require several passes.

Do you know if this action could remove all versions or will it at least leave one?

Yes, even with the initial implementation this action can very well remove all versions, for instance if numOldVersionsToDelete is set higher to the total number of packages. Leaving at least one (the latest version) would indeed be desirable, although probably out of the scope of the current PR (I can gladly prepare another PR for that though).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your valuable replies. I can see the complexities.

I find it odd that the default implementation would let you delete all versions. I'm afraid to use the action without this "protection".

Also, the numOldVersionsToDelete is kind of up-side-down isn't it? Wouldn't it make more sense with a keepNumVersions + what your PR providers?

Leaving at least one (the latest version) would indeed be desirable, although probably out of the scope of the current PR

Yeah, that would be a different PR.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

keepNumVersions has also been proposed in #5, also that one is also tricky with the current GitHub GraphQL API v4 as the API doesn't provide a way to return "all" package versions unless you call the API asking for the "first N packages" with a large enough number.

By the way, if #5 gets implemented it would also be possible to combine it with the ignore-package-names proposed in this PR.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

API doesn't provide a way to return "all" package versions unless you call the API asking for the "first N packages" with a large enough number.

I guess any, not necessarily large, number would suffice. As long as you don't add more than whatever that number is. At each delete action execution it would carve away old versions until there are no more of them. Isn't that how it would/could work?

By the way, if #5 gets implemented it would also be possible to combine it with the ignore-package-names proposed in this PR.

Good to know, thank you.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At each delete action execution it would carve away old versions until there are no more of them.

In theory yes, for instance if you set keepNumVersions to 5 and call the API every time requesting the 10 latest versions. What could possibly betray user expectations however is that this way you would end up deleting old (but not oldest) packages and slowly working your way down when the user would rather have oldest packages deleted first. Though the reality is that automation with the current API has no "one size fits all" and some users' expectations may be betrayed regardless.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. Thanks for the explanation.

map(versionInfo =>
versionInfo
.filter(info => !input.ignoredVersions.test(info.version))
.map(info => info.id)
)
)
}

return throwError(
Expand Down
4 changes: 4 additions & 0 deletions src/input.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export interface InputParams {
packageVersionIds?: string[]
ignoredVersions?: RegExp
owner?: string
repo?: string
packageName?: string
Expand All @@ -9,6 +10,7 @@ export interface InputParams {

const defaultParams = {
packageVersionIds: [],
ignoredVersions: new RegExp('^(?!.*)$'),
owner: '',
repo: '',
packageName: '',
Expand All @@ -18,6 +20,7 @@ const defaultParams = {

export class Input {
packageVersionIds: string[]
ignoredVersions: RegExp
owner: string
repo: string
packageName: string
Expand All @@ -28,6 +31,7 @@ export class Input {
const validatedParams: Required<InputParams> = {...defaultParams, ...params}

this.packageVersionIds = validatedParams.packageVersionIds
this.ignoredVersions = validatedParams.ignoredVersions
this.owner = validatedParams.owner
this.repo = validatedParams.repo
this.packageName = validatedParams.packageName
Expand Down
1 change: 1 addition & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ function getActionInput(): Input {
packageVersionIds: getInput('package-version-ids')
? getInput('package-version-ids').split(',')
: [],
ignoredVersions: RegExp(getInput('ignored-version-names')),
owner: getInput('owner') ? getInput('owner') : context.repo.owner,
repo: getInput('repo') ? getInput('repo') : context.repo.repo,
packageName: getInput('package-name'),
Expand Down