Releases/v1 (#1)

* delete package versions action v1

* updated action for build and smoke test

* test and error message update

* test fix

* ci testing

* ci testing

* ci testing

* ci testing

* ci test

* ci testing

* ci test name

* docs

* docs

* docs

* test

* test

* test

* docs

* usage doc

* doc

* docs

* format test

* doc update

* doc test

* formatting check

* scenario update

* usage update

* format

* test

* test

* test

* test

* test

* table test

* test

* format update

* links

* test

* test

* test

* test

* test

* docs update

* test

* formatting

* fix broken links

* doc update

* test

* table test

* test

* test

* test

* test

* test

* test

* test

* test

* test

* test

* doc test

* test

* test

* test

* test

* test

* test

* test

t

* test

* test

* test

* test

* test

* test

* docs

* doc update
This commit is contained in:
Trent Jones
2020-02-29 19:33:20 -06:00
committed by GitHub
parent 91c0d1036c
commit 54b504899d
21 changed files with 38317 additions and 456 deletions

41
src/delete.ts Normal file
View File

@@ -0,0 +1,41 @@
import {Input} from './input'
import {Observable, of, throwError} from 'rxjs'
import {deletePackageVersions, getOldestVersions} from './version'
import {concatMap, map} from 'rxjs/operators'
export function getVersionIds(input: Input): Observable<string[]> {
if (input.packageVersionIds.length > 0) {
return of(input.packageVersionIds)
}
if (input.hasOldestVersionQueryInfo()) {
return getOldestVersions(
input.owner,
input.repo,
input.packageName,
input.numOldVersionsToDelete,
input.token
).pipe(map(versionInfo => versionInfo.map(info => info.id)))
}
return throwError(
"Could not get packageVersionIds. Explicitly specify using the 'package-version-ids' input or provide the 'package-name' and 'num-old-versions-to-delete' inputs to dynamically retrieve oldest versions"
)
}
export function deleteVersions(input: Input): Observable<boolean> {
if (!input.token) {
return throwError('No token found')
}
if (input.numOldVersionsToDelete <= 0) {
console.log(
'Number of old versions to delete input is 0 or less, no versions will be deleted'
)
return of(true)
}
return getVersionIds(input).pipe(
concatMap(ids => deletePackageVersions(ids, input.token))
)
}

47
src/input.ts Normal file
View File

@@ -0,0 +1,47 @@
export interface InputParams {
packageVersionIds?: string[]
owner?: string
repo?: string
packageName?: string
numOldVersionsToDelete?: number
token?: string
}
const defaultParams = {
packageVersionIds: [],
owner: '',
repo: '',
packageName: '',
numOldVersionsToDelete: 0,
token: ''
}
export class Input {
packageVersionIds: string[]
owner: string
repo: string
packageName: string
numOldVersionsToDelete: number
token: string
constructor(params?: InputParams) {
const validatedParams: Required<InputParams> = {...defaultParams, ...params}
this.packageVersionIds = validatedParams.packageVersionIds
this.owner = validatedParams.owner
this.repo = validatedParams.repo
this.packageName = validatedParams.packageName
this.numOldVersionsToDelete = validatedParams.numOldVersionsToDelete
this.token = validatedParams.token
}
hasOldestVersionQueryInfo(): boolean {
return !!(
this.owner &&
this.repo &&
this.packageName &&
this.numOldVersionsToDelete > 0 &&
this.token
)
}
}

View File

@@ -1,19 +1,35 @@
import * as core from '@actions/core'
import {wait} from './wait'
import {getInput, setFailed} from '@actions/core'
import {context} from '@actions/github'
import {Input} from './input'
import {Observable, throwError} from 'rxjs'
import {deleteVersions} from './delete'
import {catchError} from 'rxjs/operators'
async function run(): Promise<void> {
function getActionInput(): Input {
return new Input({
packageVersionIds: getInput('package-version-ids')
? getInput('package-version-ids').split(',')
: [],
owner: getInput('owner') ? getInput('owner') : context.repo.owner,
repo: getInput('repo') ? getInput('repo') : context.repo.repo,
packageName: getInput('package-name'),
numOldVersionsToDelete: Number(getInput('num-old-versions-to-delete')),
token: getInput('token')
})
}
function run(): Observable<boolean> {
try {
const ms: string = core.getInput('milliseconds')
core.debug(`Waiting ${ms} milliseconds ...`)
core.debug(new Date().toTimeString())
await wait(parseInt(ms, 10))
core.debug(new Date().toTimeString())
core.setOutput('time', new Date().toTimeString())
return deleteVersions(getActionInput()).pipe(
catchError(err => throwError(err))
)
} catch (error) {
core.setFailed(error.message)
return throwError(error.message)
}
}
run()
run().subscribe({
error: err => {
setFailed(err)
}
})

View File

@@ -0,0 +1,66 @@
import {from, Observable, merge, throwError, of} from 'rxjs'
import {graphql} from '@octokit/graphql'
import {catchError, map, tap} from 'rxjs/operators'
import {GraphQlQueryResponse} from '@octokit/graphql/dist-types/types'
export interface DeletePackageVersionMutationResponse {
deletePackageVersion: {
success: boolean
}
}
const mutation = `
mutation deletePackageVersion($packageVersionId: String!) {
deletePackageVersion(input: {packageVersionId: $packageVersionId}) {
success
}
}`
export function deletePackageVersion(
packageVersionId: string,
token: string
): Observable<boolean> {
return from(
graphql(mutation, {
packageVersionId,
headers: {
authorization: `token ${token}`,
Accept: 'application/vnd.github.package-deletes-preview+json'
}
}) as Promise<DeletePackageVersionMutationResponse>
).pipe(
catchError((err: GraphQlQueryResponse) => {
const msg = 'delete version mutation failed.'
return throwError(
err.errors && err.errors.length > 0
? `${msg} ${err.errors[0].message}`
: `${msg} verify input parameters are correct`
)
}),
map(response => response.deletePackageVersion.success)
)
}
export function deletePackageVersions(
packageVersionIds: string[],
token: string
): Observable<boolean> {
if (packageVersionIds.length === 0) {
console.log('no package version ids found, no versions will be deleted')
return of(true)
}
const deletes = packageVersionIds.map(id =>
deletePackageVersion(id, token).pipe(
tap(result => {
if (result) {
console.log(`version with id: ${id}, deleted`)
} else {
console.log(`version with id: ${id}, not deleted`)
}
})
)
)
return merge(...deletes)
}

111
src/version/get-versions.ts Normal file
View File

@@ -0,0 +1,111 @@
import {graphql} from '@octokit/graphql'
import {GraphQlQueryResponse} from '@octokit/graphql/dist-types/types'
import {Observable, from, throwError} from 'rxjs'
import {catchError, map} from 'rxjs/operators'
export interface VersionInfo {
id: string
version: string
}
export interface GetVersionsQueryResponse {
repository: {
packages: {
edges: {
node: {
name: string
versions: {
edges: {node: VersionInfo}[]
}
}
}[]
}
}
}
const query = `
query getVersions($owner: String!, $repo: String!, $package: String!, $last: Int!) {
repository(owner: $owner, name: $repo) {
packages(first: 1, names: [$package]) {
edges {
node {
name
versions(last: $last) {
edges {
node {
id
version
}
}
}
}
}
}
}
}`
export function queryForOldestVersions(
owner: string,
repo: string,
packageName: string,
numVersions: number,
token: string
): Observable<GetVersionsQueryResponse> {
return from(
graphql(query, {
owner,
repo,
package: packageName,
last: numVersions,
headers: {
authorization: `token ${token}`,
Accept: 'application/vnd.github.packages-preview+json'
}
}) as Promise<GetVersionsQueryResponse>
).pipe(
catchError((err: GraphQlQueryResponse) => {
const msg = 'query for oldest version failed.'
return throwError(
err.errors && err.errors.length > 0
? `${msg} ${err.errors[0].message}`
: `${msg} verify input parameters are correct`
)
})
)
}
export function getOldestVersions(
owner: string,
repo: string,
packageName: string,
numVersions: number,
token: string
): Observable<VersionInfo[]> {
return queryForOldestVersions(
owner,
repo,
packageName,
numVersions,
token
).pipe(
map(result => {
if (result.repository.packages.edges.length < 1) {
throwError(
`package: ${packageName} not found for owner: ${owner} in repo: ${repo}`
)
}
const versions = result.repository.packages.edges[0].node.versions.edges
if (versions.length !== numVersions) {
console.log(
`number of versions requested was: ${numVersions}, but found: ${versions.length}`
)
}
return versions
.map(value => ({id: value.node.id, version: value.node.version}))
.reverse()
})
)
}

2
src/version/index.ts Normal file
View File

@@ -0,0 +1,2 @@
export * from './get-versions'
export * from './delete-version'

View File

@@ -1,9 +0,0 @@
export async function wait(milliseconds: number): Promise<string> {
return new Promise(resolve => {
if (isNaN(milliseconds)) {
throw new Error('milliseconds not a number')
}
setTimeout(() => resolve('done!'), milliseconds)
})
}