Fixes #12 Artifacts will now be replaced

This commit is contained in:
Nick Cipollo
2020-03-02 17:52:44 -05:00
parent 767a5edcf4
commit d57d57cad2
15 changed files with 265 additions and 45 deletions

View File

@@ -1,5 +1,6 @@
import { Inputs } from "./Inputs";
import { Releases } from "./Releases";
import { ReposCreateReleaseResponse } from "@octokit/rest";
import { ArtifactUploader } from "./ArtifactUploader";
import { ErrorMessage } from "./ErrorMessage";
@@ -15,15 +16,17 @@ export class Action {
}
async perform() {
const uploadUrl = await this.createOrUpdateRelease()
const releaseResponse = await this.createOrUpdateRelease();
const releaseId = releaseResponse.id
const uploadUrl = releaseResponse.upload_url
const artifacts = this.inputs.artifacts
if (artifacts.length > 0) {
await this.uploader.uploadArtifacts(artifacts, uploadUrl)
await this.uploader.uploadArtifacts(artifacts, releaseId, uploadUrl)
}
}
private async createOrUpdateRelease(): Promise<string> {
private async createOrUpdateRelease(): Promise<ReposCreateReleaseResponse> {
if (this.inputs.allowUpdates) {
try {
const getResponse = await this.releases.getByTag(this.inputs.tag)
@@ -40,7 +43,7 @@ export class Action {
}
}
private async updateRelease(id: number): Promise<string> {
private async updateRelease(id: number): Promise<ReposCreateReleaseResponse> {
const response = await this.releases.update(
id,
this.inputs.tag,
@@ -51,7 +54,7 @@ export class Action {
this.inputs.prerelease
)
return response.data.upload_url
return response.data
}
private noPublishedRelease(error: any): boolean {
@@ -59,7 +62,7 @@ export class Action {
return errorMessage.status == 404
}
private async updateDraftOrCreateRelease(): Promise<string> {
private async updateDraftOrCreateRelease(): Promise<ReposCreateReleaseResponse> {
const draftReleaseId = await this.findMatchingDraftReleaseId()
if (draftReleaseId) {
return await this.updateRelease(draftReleaseId)
@@ -77,7 +80,7 @@ export class Action {
return draftRelease?.id
}
private async createRelease(): Promise<string> {
private async createRelease(): Promise<ReposCreateReleaseResponse> {
const response = await this.releases.create(
this.inputs.tag,
this.inputs.body,
@@ -87,6 +90,6 @@ export class Action {
this.inputs.prerelease
)
return response.data.upload_url
return response.data
}
}

View File

@@ -1,30 +1,56 @@
import * as core from '@actions/core';
import { Artifact } from "./Artifact";
import { Releases } from "./Releases";
import { ReposListAssetsForReleaseResponseItem } from "@octokit/rest";
import { ErrorMessage } from './ErrorMessage';
export interface ArtifactUploader {
uploadArtifacts(artifacts: Artifact[], uploadUrl: string): Promise<void>
uploadArtifacts(artifacts: Artifact[], releaseId: number, uploadUrl: string): Promise<void>
}
export class GithubArtifactUploader implements ArtifactUploader {
private releases: Releases
private replacesExistingArtifacts: boolean = true
constructor(releases: Releases) {
constructor(releases: Releases, replacesExistingArtifacts: boolean) {
this.releases = releases
this.replacesExistingArtifacts = replacesExistingArtifacts
}
async uploadArtifacts(artifacts: Artifact[], uploadUrl: string) {
artifacts.forEach(async artifact => {
async uploadArtifacts(artifacts: Artifact[],
releaseId: number,
uploadUrl: string): Promise<void> {
if(this.replacesExistingArtifacts) {
await this.deleteUpdatedArtifacts(artifacts, releaseId)
}
for (const artifact of artifacts) {
try {
await this.releases.uploadArtifact(uploadUrl,
artifact.contentLength,
artifact.contentType,
artifact.readFile(),
artifact.name)
} catch(error) {
} catch (error) {
const message = `Failed to upload artifact ${artifact.name}. Does it already exist?`
core.warning(message)
}
}
return Promise.resolve()
}
async deleteUpdatedArtifacts(artifacts: Artifact[], releaseId: number) {
const response = await this.releases.listArtifactsForRelease(releaseId)
const releaseAssets = response.data
const assetByName = new Map<string, ReposListAssetsForReleaseResponseItem>()
releaseAssets.forEach(asset => {
assetByName[asset.name] = asset
});
for (const artifact of artifacts) {
const asset = assetByName[artifact.name]
if (asset) {
await this.releases.deleteArtifact(asset.id)
}
}
}
}

View File

@@ -12,6 +12,7 @@ export interface Inputs {
readonly draft: boolean
readonly name: string
readonly prerelease: boolean
readonly replacesArtifacts: boolean
readonly tag: string
readonly token: string
}
@@ -79,8 +80,13 @@ export class CoreInputs implements Inputs {
}
get prerelease(): boolean {
const draft = core.getInput('prerelease')
return draft == 'true'
const preRelease = core.getInput('prerelease')
return preRelease == 'true'
}
get replacesArtifacts(): boolean {
const replaces = core.getInput('replacesArtifacts')
return replaces == 'true'
}
get tag(): string {

View File

@@ -25,7 +25,7 @@ function createAction(): Action {
const inputs = new CoreInputs(globber, context)
const releases = new GithubReleases(context, git)
const uploader = new GithubArtifactUploader(releases)
const uploader = new GithubArtifactUploader(releases, inputs.replacesArtifacts)
return new Action(inputs, releases, uploader)
}

View File

@@ -1,6 +1,6 @@
import { Context } from "@actions/github/lib/context";
import { GitHub } from "@actions/github";
import { AnyResponse, Response, ReposCreateReleaseResponse, ReposGetReleaseByTagResponse, ReposListReleasesResponse } from "@octokit/rest";
import { AnyResponse, Response, ReposDeleteReleaseAssetResponse, ReposListAssetsForReleaseResponse, ReposCreateReleaseResponse, ReposGetReleaseByTagResponse, ReposListReleasesResponse } from "@octokit/rest";
export interface Releases {
create(
@@ -12,8 +12,12 @@ export interface Releases {
prerelease?: boolean
): Promise<Response<ReposCreateReleaseResponse>>
deleteArtifact(assetId: number): Promise<Response<ReposDeleteReleaseAssetResponse>>
getByTag(tag: string): Promise<Response<ReposGetReleaseByTagResponse>>
listArtifactsForRelease(releaseId: number): Promise<Response<ReposListAssetsForReleaseResponse>>
listReleases(): Promise<Response<ReposListReleasesResponse>>
update(
@@ -64,6 +68,26 @@ export class GithubReleases implements Releases {
})
}
async deleteArtifact(
assetId: number
): Promise<Response<ReposDeleteReleaseAssetResponse>> {
return this.git.repos.deleteReleaseAsset({
asset_id: assetId,
owner: this.context.repo.owner,
repo: this.context.repo.repo
})
}
async listArtifactsForRelease(
releaseId: number
): Promise<Response<ReposListAssetsForReleaseResponse>> {
return this.git.repos.listAssetsForRelease({
owner: this.context.repo.owner,
release_id: releaseId,
repo: this.context.repo.repo
})
}
async listReleases(): Promise<Response<ReposListReleasesResponse>> {
return this.git.repos.listReleases({
owner: this.context.repo.owner,