Fixes #6 Add support for updating releases
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import { Inputs } from "./Inputs";
|
||||
import { Releases } from "./Releases";
|
||||
import { ArtifactUploader } from "./ArtifactUploader";
|
||||
import { ErrorMessage } from "./ErrorMessage";
|
||||
import { Response, ReposCreateReleaseResponse } from "@octokit/rest";
|
||||
|
||||
export class Action {
|
||||
private inputs: Inputs
|
||||
@@ -14,7 +16,28 @@ export class Action {
|
||||
}
|
||||
|
||||
async perform() {
|
||||
const createResult = await this.releases.create(
|
||||
const uploadUrl = await this.createOrUpdateRelease()
|
||||
|
||||
const artifacts = this.inputs.artifacts
|
||||
if (artifacts.length > 0) {
|
||||
await this.uploader.uploadArtifacts(artifacts, uploadUrl)
|
||||
}
|
||||
}
|
||||
|
||||
private async createOrUpdateRelease(): Promise<string> {
|
||||
try {
|
||||
return await this.createRelease()
|
||||
} catch (error) {
|
||||
if (this.releaseAlreadyExisted(error) && this.inputs.allowUpdates) {
|
||||
return this.updateRelease()
|
||||
} else {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async createRelease(): Promise<string> {
|
||||
const response = await this.releases.create(
|
||||
this.inputs.tag,
|
||||
this.inputs.body,
|
||||
this.inputs.commit,
|
||||
@@ -22,12 +45,27 @@ export class Action {
|
||||
this.inputs.name
|
||||
)
|
||||
|
||||
const artifacts = this.inputs.artifacts
|
||||
if (artifacts.length > 0) {
|
||||
await this.uploader.uploadArtifacts(
|
||||
artifacts,
|
||||
createResult.data.upload_url
|
||||
)
|
||||
}
|
||||
return response.data.upload_url
|
||||
}
|
||||
|
||||
private releaseAlreadyExisted(error: any): boolean {
|
||||
const errorMessage = new ErrorMessage(error)
|
||||
return errorMessage.hasErrorWithCode('already_exists')
|
||||
}
|
||||
|
||||
private async updateRelease(): Promise<string> {
|
||||
const getResponse = await this.releases.getByTag(this.inputs.tag)
|
||||
const id = getResponse.data.id
|
||||
|
||||
const response = await this.releases.update(
|
||||
id,
|
||||
this.inputs.tag,
|
||||
this.inputs.body,
|
||||
this.inputs.commit,
|
||||
this.inputs.draft,
|
||||
this.inputs.name
|
||||
)
|
||||
|
||||
return response.data.upload_url
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import { Artifact } from "./Artifact";
|
||||
import { Releases } from "./Releases";
|
||||
|
||||
export interface ArtifactUploader {
|
||||
uploadArtifacts(artifacts: Artifact[], uploadUrl: string): void
|
||||
uploadArtifacts(artifacts: Artifact[], uploadUrl: string): Promise<void>
|
||||
}
|
||||
|
||||
export class GithubArtifactUploader implements ArtifactUploader {
|
||||
|
||||
@@ -1,23 +1,15 @@
|
||||
import { GithubError } from "./GithubError"
|
||||
|
||||
export class ErrorMessage {
|
||||
error: any
|
||||
private error: any
|
||||
private githubErrors: GithubError[]
|
||||
|
||||
constructor(error: any) {
|
||||
this.error = error
|
||||
this.githubErrors = this.generateGithubErrors()
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
const message = this.error.message
|
||||
const errors = this.githubErrors()
|
||||
if (errors.length > 0) {
|
||||
return `${message}\nErrors:\n${this.errorBulletedList(errors)}`
|
||||
} else {
|
||||
return message
|
||||
}
|
||||
}
|
||||
|
||||
githubErrors(): GithubError[] {
|
||||
private generateGithubErrors(): GithubError[] {
|
||||
const errors = this.error.errors
|
||||
if (errors instanceof Array) {
|
||||
return errors.map((err) => new GithubError(err))
|
||||
@@ -26,7 +18,21 @@ export class ErrorMessage {
|
||||
}
|
||||
}
|
||||
|
||||
errorBulletedList(errors: GithubError[]): string {
|
||||
hasErrorWithCode(code: String): boolean {
|
||||
return this.githubErrors.some((err) => err.code == code)
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
const message = this.error.message
|
||||
const errors = this.githubErrors
|
||||
if (errors.length > 0) {
|
||||
return `${message}\nErrors:\n${this.errorBulletedList(errors)}`
|
||||
} else {
|
||||
return message
|
||||
}
|
||||
}
|
||||
|
||||
private errorBulletedList(errors: GithubError[]): string {
|
||||
return errors.map((err) => `- ${err}`).join("\n")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
export class GithubError {
|
||||
error: any;
|
||||
private error: any;
|
||||
|
||||
constructor(error: any) {
|
||||
this.error = error
|
||||
}
|
||||
|
||||
get code(): string {
|
||||
return this.error.code
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
const code = this.error.code
|
||||
switch(code) {
|
||||
const code = this.error.code
|
||||
switch (code) {
|
||||
case 'missing':
|
||||
return this.missingResourceMessage()
|
||||
case 'missing_field':
|
||||
@@ -26,7 +30,7 @@ export class GithubError {
|
||||
const documentation = this.error.documentation_url
|
||||
|
||||
let documentationMessage: string
|
||||
if(documentation) {
|
||||
if (documentation) {
|
||||
documentationMessage = `\nPlease see ${documentation}.`
|
||||
} else {
|
||||
documentationMessage = ""
|
||||
@@ -41,7 +45,7 @@ export class GithubError {
|
||||
|
||||
return `The ${field} field on ${resource} is an invalid format.`
|
||||
}
|
||||
|
||||
|
||||
private missingResourceMessage(): string {
|
||||
const resource = this.error.resource
|
||||
return `${resource} does not exist.`
|
||||
|
||||
@@ -5,6 +5,7 @@ import { ArtifactGlobber } from './ArtifactGlobber';
|
||||
import { Artifact } from './Artifact';
|
||||
|
||||
export interface Inputs {
|
||||
readonly allowUpdates: boolean
|
||||
readonly artifacts: Artifact[]
|
||||
readonly body: string
|
||||
readonly commit: string
|
||||
@@ -23,6 +24,11 @@ export class CoreInputs implements Inputs {
|
||||
this.context = context
|
||||
}
|
||||
|
||||
get allowUpdates(): boolean {
|
||||
const allow = core.getInput('allowUpdates')
|
||||
return allow == 'true'
|
||||
}
|
||||
|
||||
get artifacts(): Artifact[] {
|
||||
let artifacts = core.getInput('artifacts')
|
||||
if (!artifacts) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Context } from "@actions/github/lib/context";
|
||||
import { GitHub } from "@actions/github";
|
||||
import { AnyResponse, Response, ReposCreateReleaseResponse } from "@octokit/rest";
|
||||
import { AnyResponse, Response, ReposCreateReleaseResponse, ReposGetReleaseByTagResponse } from "@octokit/rest";
|
||||
|
||||
export interface Releases {
|
||||
create(
|
||||
@@ -11,6 +11,17 @@ export interface Releases {
|
||||
name?: string
|
||||
): Promise<Response<ReposCreateReleaseResponse>>
|
||||
|
||||
getByTag(tag: string): Promise<Response<ReposGetReleaseByTagResponse>>
|
||||
|
||||
update(
|
||||
id: number,
|
||||
tag: string,
|
||||
body?: string,
|
||||
commitHash?: string,
|
||||
draft?: boolean,
|
||||
name?: string
|
||||
): Promise<Response<ReposCreateReleaseResponse>>
|
||||
|
||||
uploadArtifact(
|
||||
assetUrl: string,
|
||||
contentLength: number,
|
||||
@@ -20,7 +31,7 @@ export interface Releases {
|
||||
): Promise<Response<AnyResponse>>
|
||||
}
|
||||
|
||||
export class GithubReleases implements Releases{
|
||||
export class GithubReleases implements Releases {
|
||||
context: Context
|
||||
git: GitHub
|
||||
|
||||
@@ -47,6 +58,34 @@ export class GithubReleases implements Releases{
|
||||
})
|
||||
}
|
||||
|
||||
async getByTag(tag: string): Promise<Response<ReposGetReleaseByTagResponse>> {
|
||||
return this.git.repos.getReleaseByTag({
|
||||
owner: this.context.repo.owner,
|
||||
repo: this.context.repo.repo,
|
||||
tag: tag
|
||||
})
|
||||
}
|
||||
|
||||
async update(
|
||||
id: number,
|
||||
tag: string,
|
||||
body?: string,
|
||||
commitHash?: string,
|
||||
draft?: boolean,
|
||||
name?: string
|
||||
): Promise<Response<ReposCreateReleaseResponse>> {
|
||||
return this.git.repos.updateRelease({
|
||||
release_id: id,
|
||||
body: body,
|
||||
name: name,
|
||||
draft: draft,
|
||||
owner: this.context.repo.owner,
|
||||
repo: this.context.repo.repo,
|
||||
target_commitish: commitHash,
|
||||
tag_name: tag
|
||||
})
|
||||
}
|
||||
|
||||
async uploadArtifact(
|
||||
assetUrl: string,
|
||||
contentLength: number,
|
||||
|
||||
Reference in New Issue
Block a user