@actions/artifact package updates (#408)

* Clear error message when storage quota has been hit

* Improved download of empty files

* Extra info to RELEASES.md

* PR Feedback
This commit is contained in:
Konrad Pabjan
2020-04-09 17:14:12 +02:00
committed by GitHub
parent 1b521c4778
commit c010a271d9
10 changed files with 180 additions and 20 deletions

View File

@@ -8,7 +8,11 @@ import {UploadResponse} from './upload-response'
import {UploadOptions} from './upload-options'
import {DownloadOptions} from './download-options'
import {DownloadResponse} from './download-response'
import {checkArtifactName, createDirectoriesForArtifact} from './utils'
import {
checkArtifactName,
createDirectoriesForArtifact,
createEmptyFilesForArtifact
} from './utils'
import {DownloadHttpClient} from './download-http-client'
import {getDownloadSpecification} from './download-specification'
import {getWorkSpaceDirectory} from './config-variables'
@@ -174,6 +178,9 @@ export class DefaultArtifactClient implements ArtifactClient {
downloadSpecification.directoryStructure
)
core.info('Directory structure has been setup for the artifact')
await createEmptyFilesForArtifact(
downloadSpecification.emptyFilesToCreate
)
await downloadHttpClient.downloadSingleArtifact(
downloadSpecification.filesToDownload
)
@@ -228,6 +235,9 @@ export class DefaultArtifactClient implements ArtifactClient {
await createDirectoriesForArtifact(
downloadSpecification.directoryStructure
)
await createEmptyFilesForArtifact(
downloadSpecification.emptyFilesToCreate
)
await downloadHttpClient.downloadSingleArtifact(
downloadSpecification.filesToDownload
)

View File

@@ -8,6 +8,9 @@ export interface DownloadSpecification {
// directories that need to be created for all the items in the artifact
directoryStructure: string[]
// empty files that are part of the artifact that don't require any downloading
emptyFilesToCreate: string[]
// individual files that need to be downloaded as part of the artifact
filesToDownload: DownloadItem[]
}
@@ -33,6 +36,7 @@ export function getDownloadSpecification(
downloadPath: string,
includeRootDirectory: boolean
): DownloadSpecification {
// use a set for the directory paths so that there are no duplicates
const directories = new Set<string>()
const specifications: DownloadSpecification = {
@@ -40,6 +44,7 @@ export function getDownloadSpecification(
? path.join(downloadPath, artifactName)
: downloadPath,
directoryStructure: [],
emptyFilesToCreate: [],
filesToDownload: []
}
@@ -64,11 +69,15 @@ export function getDownloadSpecification(
if (entry.itemType === 'file') {
// Get the directories that we need to create from the filePath for each individual file
directories.add(path.dirname(filePath))
specifications.filesToDownload.push({
sourceLocation: entry.contentLocation,
targetPath: filePath
})
if (entry.fileLength === 0) {
// An empty file was uploaded, create the empty files locally so that no extra http calls are made
specifications.emptyFilesToCreate.push(filePath)
} else {
specifications.filesToDownload.push({
sourceLocation: entry.contentLocation,
targetPath: filePath
})
}
}
}
}

View File

@@ -15,6 +15,7 @@ import {
isRetryableStatusCode,
isSuccessStatusCode,
isThrottledStatusCode,
isForbiddenStatusCode,
displayHttpDiagnostics,
getExponentialRetryTimeInMilliseconds,
tryGetRetryAfterValueTimeInMilliseconds
@@ -68,6 +69,12 @@ export class UploadHttpClient {
if (isSuccessStatusCode(rawResponse.message.statusCode) && body) {
return JSON.parse(body)
} else if (isForbiddenStatusCode(rawResponse.message.statusCode)) {
// if a 403 is returned when trying to create a file container, the customer has exceeded
// their storage quota so no new artifact containers can be created
throw new Error(
`Artifact storage quota has been hit. Unable to upload any new artifacts`
)
} else {
displayHttpDiagnostics(rawResponse)
throw new Error(

View File

@@ -58,6 +58,14 @@ export function isSuccessStatusCode(statusCode?: number): boolean {
return statusCode >= 200 && statusCode < 300
}
export function isForbiddenStatusCode(statusCode?: number): boolean {
if (!statusCode) {
return false
}
return statusCode === HttpCodes.Forbidden
}
export function isRetryableStatusCode(statusCode?: number): boolean {
if (!statusCode) {
return false
@@ -296,3 +304,11 @@ export async function createDirectoriesForArtifact(
})
}
}
export async function createEmptyFilesForArtifact(
emptyFilesToCreate: string[]
): Promise<void> {
for (const filePath of emptyFilesToCreate) {
await (await fs.open(filePath, 'w')).close()
}
}