Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support multiple packages #72

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open
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
57 changes: 52 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ This action deletes versions of a package from [GitHub Packages](https://github.
* Delete all package versions except n most recent versions
* Delete oldest version(s)
* Ignore version(s) from deletion through regex
* 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
* Delete version(s) of packages that are hosted in the same repo that is executing the workflow
* Delete version(s) of packages that are hosted in a different repo than the one executing the workflow
* Delete a single version
* Delete multiple versions
* Delete specific version(s)
Expand All @@ -35,9 +35,20 @@ This action deletes versions of a package from [GitHub Packages](https://github.

# Name of the package.
# Defaults to an empty string.
# Required if `package-version-ids` input is not given.
# Required if `package-version-ids` or `package-names` input is not given.
package-name:

# Names of the package.
# Can be one of the following:
# - a single package name
# - a group of packages that matches a wildcard at start, end, both sides, or all packages (e.g. "package*")
# - a group of packages that matches a regex, must start with slash at the beginning and end (e.g. "/package.*/")
# - a comma separated list of the previous cases (e.g. "package-lorem, *-ipsum, /.*dolor/")
# Defaults to an empty string.
# Required if `package-version-ids` or `package-name` input is not given.
package-names:


# The number of old versions to delete starting from the oldest version.
# Defaults to 1.
num-old-versions-to-delete:
Expand Down Expand Up @@ -70,7 +81,7 @@ This action deletes versions of a package from [GitHub Packages](https://github.

# Valid Input Combinations

`owner`, `repo`, `package-name` and `token` can be used with the following combinations in a workflow -
`owner`, `repo`, `package-name` (or `package-names`) and `token` can be used with the following combinations in a workflow -

- `num-old-versions-to-delete`
- `min-versions-to-keep`
Expand All @@ -86,12 +97,13 @@ This action deletes versions of a package from [GitHub Packages](https://github.
- [Delete all except y latest versions while ignoring particular package versions](#delete-all-except-y-latest-versions-while-ignoring-particular-package-versions)
- [Delete oldest x number of versions while ignoring particular package versions](#delete-oldest-x-number-of-versions-while-ignoring-particular-package-versions)
- [Delete all except y latest versions of a package](#delete-all-except-y-latest-versions-of-a-package)
- [Delete all except y latest versions of all packages in a repo](#delete-all-except-y-latest-versions-of-all-packages-in-a-repo)
- [Delete oldest x number of versions of a package](#delete-oldest-x-number-of-versions-of-a-package)
- [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 pre-release versions except y latest pre-release package versions

To delete all pre release versions except y latest pre-release package versions in the same repo as the workflow the __package-name__, __min-versions-to-keep__ and __delete-only-pre-release-versions__ inputs are required.
Expand Down Expand Up @@ -241,6 +253,41 @@ This action deletes versions of a package from [GitHub Packages](https://github.

<br>

### Delete all except y latest versions of a package

To delete all except y latest versions of all packages hosted in the same repo as the workflow the __package-names__ and __min-versions-to-keep__ inputs are required.

__Example__

Delete all except latest 2 versions of a package hosted in the same repo as the workflow

```yaml
- uses: actions/delete-package-versions@v3
with:
package-names: '*'
min-versions-to-keep: 2
```

To delete all except y latest versions of all packages hosted in a repo other than the workflow the __owner__, __repo__, __package-names__, __token__ and __min-versions-to-keep__ inputs are required.

The [token][token] needs the delete packages and read packages scope. It is recommended [to store the token as a secret][secret]. In this example the [token][token] was stored as a secret named __GITHUB_PAT__.

__Example__

Delete all except latest 2 versions of a package hosted in a repo other than the workflow

```yaml
- uses: actions/delete-package-versions@v3
with:
owner: 'github'
repo: 'packages'
package-names: '*'
token: ${{ secrets.PAT }}
min-versions-to-keep: 2
```

<br>

### Delete oldest x number of versions of a package

To delete the oldest x number of versions of a package hosted in the same repo as the workflow the __package-name__, and __num-old-versions-to-delete__ inputs are required.
Expand Down
66 changes: 66 additions & 0 deletions __tests__/packages/get-packages.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import {mockPackagesQueryResponse} from './graphql.mock'
import {
getRepoPackages as _getRepoPackages,
QueryInfo
} from '../../src/packages'
import {Observable} from 'rxjs'

describe.skip('get versions tests -- call graphql', () => {
it('getRepoPackages -- succeeds', done => {
const numPackages = 1
getRepoPackages({numPackages}).subscribe(result => {
expect(result.packages.length).toBe(numPackages)
done()
})
})

it('getRepoPackages -- fails for invalid repo', done => {
getRepoPackages({repo: 'actions-testin'}).subscribe({
error: err => {
expect(err).toBeTruthy()
done()
},
complete: async () => done.fail('no error thrown')
})
})
})

describe('get versions tests -- mock graphql', () => {
it('getRepoPackages -- success', done => {
const numPackages = 5
mockPackagesQueryResponse(numPackages)

getRepoPackages({numPackages}).subscribe(result => {
expect(result.packages.length).toBe(numPackages)
done()
})
})
})

interface Params {
owner?: string
repo?: string
numPackages?: number
startCursor?: string
token?: string
}

const defaultParams = {
owner: 'namratajha',
repo: 'test-repo',
packageName: 'test-repo',
numPackages: 1,
startCursor: '',
token: process.env.GITHUB_TOKEN as string
}

function getRepoPackages(params?: Params): Observable<QueryInfo> {
const p: Required<Params> = {...defaultParams, ...params}
return _getRepoPackages(
p.owner,
p.repo,
p.numPackages,
p.startCursor,
p.token
)
}
44 changes: 44 additions & 0 deletions __tests__/packages/graphql.mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import {
GraphQlQueryResponseData,
RequestParameters
} from '@octokit/graphql/dist-types/types'

import * as Graphql from '../../src/common/graphql'
import {GetPackagesQueryResponse} from '../../src/packages'

export function getMockedPackagesQueryResponse(
numPackages: number
): GetPackagesQueryResponse {
const packages = []
for (let i = 1; i <= numPackages; ++i) {
packages.push({
node: {
id: i.toString(),
name: `package${i}`
}
})
}

return {
repository: {
packages: {
pageInfo: {
endCursor: 'AAA',
hasNextPage: false
},
edges: packages
}
}
}
}

export function mockPackagesQueryResponse(numVersions: number): void {
const response = new Promise<GetPackagesQueryResponse>(resolve => {
resolve(getMockedPackagesQueryResponse(numVersions))
}) as Promise<GraphQlQueryResponseData>
jest
.spyOn(Graphql, 'graphql')
.mockImplementation(
(token: string, query: string, parameters: RequestParameters) => response
)
}
114 changes: 114 additions & 0 deletions __tests__/packages/package-name-filter.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { getPackageNameFilter } from '../../src/packages'

describe('package name filter -- create filter', () => {

const packageNameList = [
'com.company.project.module1.package1',
'com.company.project.module1.package2',
'com.company.project.module2.package1',
'com.company.project.module2.package2',
'com.company.project.module3.package-name-lorem',
'com.company.project.module3.package-name-ipsum',
'com.company.project.module3.package-name-dolor',
]

it('getPackageNameFilter -- wildcard end filter', done => {
const filter = getPackageNameFilter('com.company.project.module1.*')

const result = packageNameList.filter(filter.apply);

expect(filter.subfilters[0].type).toBe('wildcard')
expect(result).toEqual([
'com.company.project.module1.package1',
'com.company.project.module1.package2',
])
done()
})

it('getPackageNameFilter -- wildcard start filter', done => {
const filter = getPackageNameFilter('*.package1')

const result = packageNameList.filter(filter.apply);

expect(filter.subfilters[0].type).toBe('wildcard')
expect(result).toEqual([
'com.company.project.module1.package1',
'com.company.project.module2.package1',
])
done()
})

it('getPackageNameFilter -- wildcard both sides filter', done => {
const filter = getPackageNameFilter('*.project.module3.*')

const result = packageNameList.filter(filter.apply);

expect(filter.subfilters[0].type).toBe('wildcard')
expect(result).toEqual([
'com.company.project.module3.package-name-lorem',
'com.company.project.module3.package-name-ipsum',
'com.company.project.module3.package-name-dolor'
])
done()
})


it('getPackageNameFilter -- wildcard all filter', done => {
const filter = getPackageNameFilter('*')

const result = packageNameList.filter(filter.apply);

expect(filter.subfilters[0].type).toBe('wildcard')
expect(result).toEqual(packageNameList.slice())
done()
})

it('getPackageNameFilter -- regex filter', done => {
const filter = getPackageNameFilter('/com\\.company\\.project\\.module.*\\.package1/')
const result = packageNameList.filter(filter.apply);

expect(filter.subfilters[0].type).toBe('regex')
expect(result).toEqual([
'com.company.project.module1.package1',
'com.company.project.module2.package1',
])
done()
})

it('getPackageNameFilter -- exact match filter', done => {
const filter = getPackageNameFilter('com.company.project.module1.package1')
const result = packageNameList.filter(filter.apply);

expect(filter.subfilters[0].type).toBe('string')
expect(result).toEqual(['com.company.project.module1.package1'])
done()
})


it('getPackageNameFilter -- multiple filters', done => {
const filter = getPackageNameFilter('com.company.project.module1.package1, com.company.project.module2.*, /.*module3.*-ipsum/')
const result = packageNameList.filter(filter.apply);

expect(filter.subfilters.length).toBe(3)
expect(filter.subfilters[0].type).toBe('string')
expect(filter.subfilters[1].type).toBe('wildcard')
expect(filter.subfilters[2].type).toBe('regex')
expect(result).toEqual([
'com.company.project.module1.package1',
'com.company.project.module2.package1',
'com.company.project.module2.package2',
'com.company.project.module3.package-name-ipsum'
])
done()
})


it('getPackageNameFilter -- memoization, same input shoud return same output', done => {
const filterText = 'com.company.project.module1.package1, com.company.project.module2.*, /.*module3.*-dolor/, *.-lorem'
const filter1 = getPackageNameFilter(filterText)
const filter2 = getPackageNameFilter(filterText)
expect(filter1).toBe(filter2)
expect(filter1.subfilters.length).toBe(4)
done()
})
})
2 changes: 1 addition & 1 deletion __tests__/version/graphql.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
RequestParameters
} from '@octokit/graphql/dist-types/types'

import * as Graphql from '../../src/version/graphql'
import * as Graphql from '../../src/common/graphql'
import {GetVersionsQueryResponse} from '../../src/version'

export function getMockedOldestQueryResponse(
Expand Down
13 changes: 13 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,19 @@ inputs:
Required if dynamically deleting oldest versions.
required: false


package-names:
description: >
Names of the package.
Can be one of the following:
- a single package name
- a group of packages that matches a wildcard at start, end, both sides, or all packages (e.g. "package*")
- a group of packages that matches a regex, must start with slash at the beginning and end (e.g. "/package.*/")
- a comma separated list of the previous cases (e.g. "package-lorem, *-ipsum, /.*dolor/")
Defaults to an empty string.
Required if `package-version-ids` or `package-name` input is not given.
required: false

num-old-versions-to-delete:
description: >
Number of versions to delete starting with the oldest version.
Expand Down
Loading