2021-05-24 17:26:13 +01:00
"use strict" ;
var _ _awaiter = ( this && this . _ _awaiter ) || function ( thisArg , _arguments , P , generator ) {
function adopt ( value ) { return value instanceof P ? value : new P ( function ( resolve ) { resolve ( value ) ; } ) ; }
return new ( P || ( P = Promise ) ) ( function ( resolve , reject ) {
function fulfilled ( value ) { try { step ( generator . next ( value ) ) ; } catch ( e ) { reject ( e ) ; } }
function rejected ( value ) { try { step ( generator [ "throw" ] ( value ) ) ; } catch ( e ) { reject ( e ) ; } }
function step ( result ) { result . done ? resolve ( result . value ) : adopt ( result . value ) . then ( fulfilled , rejected ) ; }
step ( ( generator = generator . apply ( thisArg , _arguments || [ ] ) ) . next ( ) ) ;
} ) ;
} ;
Object . defineProperty ( exports , "__esModule" , { value : true } ) ;
const core _1 = require ( "@actions/core" ) ;
const fs _1 = require ( "fs" ) ;
const http _client _1 = require ( "@actions/http-client" ) ;
const auth _1 = require ( "@actions/http-client/auth" ) ;
const config _variables _1 = require ( "./config-variables" ) ;
/**
* Returns a retry time in milliseconds that exponentially gets larger
* depending on the amount of retries that have been attempted
*/
function getExponentialRetryTimeInMilliseconds ( retryCount ) {
if ( retryCount < 0 ) {
throw new Error ( 'RetryCount should not be negative' ) ;
}
else if ( retryCount === 0 ) {
return config _variables _1 . getInitialRetryIntervalInMilliseconds ( ) ;
}
const minTime = config _variables _1 . getInitialRetryIntervalInMilliseconds ( ) * config _variables _1 . getRetryMultiplier ( ) * retryCount ;
const maxTime = minTime * config _variables _1 . getRetryMultiplier ( ) ;
// returns a random number between the minTime (inclusive) and the maxTime (exclusive)
return Math . random ( ) * ( maxTime - minTime ) + minTime ;
}
exports . getExponentialRetryTimeInMilliseconds = getExponentialRetryTimeInMilliseconds ;
/**
* Parses a env variable that is a number
*/
function parseEnvNumber ( key ) {
const value = Number ( process . env [ key ] ) ;
if ( Number . isNaN ( value ) || value < 0 ) {
return undefined ;
}
return value ;
}
exports . parseEnvNumber = parseEnvNumber ;
/**
* Various utility functions to help with the necessary API calls
*/
function getApiVersion ( ) {
return '6.0-preview' ;
}
exports . getApiVersion = getApiVersion ;
function isSuccessStatusCode ( statusCode ) {
if ( ! statusCode ) {
return false ;
}
return statusCode >= 200 && statusCode < 300 ;
}
exports . isSuccessStatusCode = isSuccessStatusCode ;
function isForbiddenStatusCode ( statusCode ) {
if ( ! statusCode ) {
return false ;
}
return statusCode === http _client _1 . HttpCodes . Forbidden ;
}
exports . isForbiddenStatusCode = isForbiddenStatusCode ;
function isRetryableStatusCode ( statusCode ) {
if ( ! statusCode ) {
return false ;
}
const retryableStatusCodes = [
http _client _1 . HttpCodes . BadGateway ,
http _client _1 . HttpCodes . GatewayTimeout ,
2021-07-27 22:24:53 +00:00
http _client _1 . HttpCodes . InternalServerError ,
http _client _1 . HttpCodes . ServiceUnavailable ,
2021-05-24 17:26:13 +01:00
http _client _1 . HttpCodes . TooManyRequests ,
413 // Payload Too Large
] ;
return retryableStatusCodes . includes ( statusCode ) ;
}
exports . isRetryableStatusCode = isRetryableStatusCode ;
function isThrottledStatusCode ( statusCode ) {
if ( ! statusCode ) {
return false ;
}
return statusCode === http _client _1 . HttpCodes . TooManyRequests ;
}
exports . isThrottledStatusCode = isThrottledStatusCode ;
/**
* Attempts to get the retry-after value from a set of http headers. The retry time
* is originally denoted in seconds, so if present, it is converted to milliseconds
* @param headers all the headers received when making an http call
*/
function tryGetRetryAfterValueTimeInMilliseconds ( headers ) {
if ( headers [ 'retry-after' ] ) {
const retryTime = Number ( headers [ 'retry-after' ] ) ;
if ( ! isNaN ( retryTime ) ) {
core _1 . info ( ` Retry-After header is present with a value of ${ retryTime } ` ) ;
return retryTime * 1000 ;
}
core _1 . info ( ` Returned retry-after header value: ${ retryTime } is non-numeric and cannot be used ` ) ;
return undefined ;
}
core _1 . info ( ` No retry-after header was found. Dumping all headers for diagnostic purposes ` ) ;
// eslint-disable-next-line no-console
console . log ( headers ) ;
return undefined ;
}
exports . tryGetRetryAfterValueTimeInMilliseconds = tryGetRetryAfterValueTimeInMilliseconds ;
function getContentRange ( start , end , total ) {
// Format: `bytes start-end/fileSize
// start and end are inclusive
// For a 200 byte chunk starting at byte 0:
// Content-Range: bytes 0-199/200
return ` bytes ${ start } - ${ end } / ${ total } ` ;
}
exports . getContentRange = getContentRange ;
/**
* Sets all the necessary headers when downloading an artifact
* @param {string} contentType the type of content being uploaded
* @param {boolean} isKeepAlive is the same connection being used to make multiple calls
* @param {boolean} acceptGzip can we accept a gzip encoded response
* @param {string} acceptType the type of content that we can accept
* @returns appropriate headers to make a specific http call during artifact download
*/
function getDownloadHeaders ( contentType , isKeepAlive , acceptGzip ) {
const requestOptions = { } ;
if ( contentType ) {
requestOptions [ 'Content-Type' ] = contentType ;
}
if ( isKeepAlive ) {
requestOptions [ 'Connection' ] = 'Keep-Alive' ;
// keep alive for at least 10 seconds before closing the connection
requestOptions [ 'Keep-Alive' ] = '10' ;
}
if ( acceptGzip ) {
// if we are expecting a response with gzip encoding, it should be using an octet-stream in the accept header
requestOptions [ 'Accept-Encoding' ] = 'gzip' ;
requestOptions [ 'Accept' ] = ` application/octet-stream;api-version= ${ getApiVersion ( ) } ` ;
}
else {
// default to application/json if we are not working with gzip content
requestOptions [ 'Accept' ] = ` application/json;api-version= ${ getApiVersion ( ) } ` ;
}
return requestOptions ;
}
exports . getDownloadHeaders = getDownloadHeaders ;
/**
* Sets all the necessary headers when uploading an artifact
* @param {string} contentType the type of content being uploaded
* @param {boolean} isKeepAlive is the same connection being used to make multiple calls
* @param {boolean} isGzip is the connection being used to upload GZip compressed content
* @param {number} uncompressedLength the original size of the content if something is being uploaded that has been compressed
* @param {number} contentLength the length of the content that is being uploaded
* @param {string} contentRange the range of the content that is being uploaded
* @returns appropriate headers to make a specific http call during artifact upload
*/
function getUploadHeaders ( contentType , isKeepAlive , isGzip , uncompressedLength , contentLength , contentRange ) {
const requestOptions = { } ;
requestOptions [ 'Accept' ] = ` application/json;api-version= ${ getApiVersion ( ) } ` ;
if ( contentType ) {
requestOptions [ 'Content-Type' ] = contentType ;
}
if ( isKeepAlive ) {
requestOptions [ 'Connection' ] = 'Keep-Alive' ;
// keep alive for at least 10 seconds before closing the connection
requestOptions [ 'Keep-Alive' ] = '10' ;
}
if ( isGzip ) {
requestOptions [ 'Content-Encoding' ] = 'gzip' ;
requestOptions [ 'x-tfs-filelength' ] = uncompressedLength ;
}
if ( contentLength ) {
requestOptions [ 'Content-Length' ] = contentLength ;
}
if ( contentRange ) {
requestOptions [ 'Content-Range' ] = contentRange ;
}
return requestOptions ;
}
exports . getUploadHeaders = getUploadHeaders ;
function createHttpClient ( userAgent ) {
return new http _client _1 . HttpClient ( userAgent , [
new auth _1 . BearerCredentialHandler ( config _variables _1 . getRuntimeToken ( ) )
] ) ;
}
exports . createHttpClient = createHttpClient ;
function getArtifactUrl ( ) {
const artifactUrl = ` ${ config _variables _1 . getRuntimeUrl ( ) } _apis/pipelines/workflows/ ${ config _variables _1 . getWorkFlowRunId ( ) } /artifacts?api-version= ${ getApiVersion ( ) } ` ;
core _1 . debug ( ` Artifact Url: ${ artifactUrl } ` ) ;
return artifactUrl ;
}
exports . getArtifactUrl = getArtifactUrl ;
/**
* Uh oh! Something might have gone wrong during either upload or download. The IHtttpClientResponse object contains information
* about the http call that was made by the actions http client. This information might be useful to display for diagnostic purposes, but
* this entire object is really big and most of the information is not really useful. This function takes the response object and displays only
* the information that we want.
*
* Certain information such as the TLSSocket and the Readable state are not really useful for diagnostic purposes so they can be avoided.
* Other information such as the headers, the response code and message might be useful, so this is displayed.
*/
function displayHttpDiagnostics ( response ) {
core _1 . info ( ` ##### Begin Diagnostic HTTP information #####
Status Code: ${ response . message . statusCode }
Status Message: ${ response . message . statusMessage }
Header Information: ${ JSON . stringify ( response . message . headers , undefined , 2 ) }
###### End Diagnostic HTTP information ###### ` ) ;
}
exports . displayHttpDiagnostics = displayHttpDiagnostics ;
/**
* Invalid characters that cannot be in the artifact name or an uploaded file. Will be rejected
* from the server if attempted to be sent over. These characters are not allowed due to limitations with certain
* file systems such as NTFS. To maintain platform-agnostic behavior, all characters that are not supported by an
* individual filesystem/platform will not be supported on all fileSystems/platforms
*
* FilePaths can include characters such as \ and / which are not permitted in the artifact name alone
*/
const invalidArtifactFilePathCharacters = [ '"' , ':' , '<' , '>' , '|' , '*' , '?' ] ;
const invalidArtifactNameCharacters = [
... invalidArtifactFilePathCharacters ,
'\\' ,
'/'
] ;
/**
* Scans the name of the artifact to make sure there are no illegal characters
*/
function checkArtifactName ( name ) {
if ( ! name ) {
throw new Error ( ` Artifact name: ${ name } , is incorrectly provided ` ) ;
}
for ( const invalidChar of invalidArtifactNameCharacters ) {
if ( name . includes ( invalidChar ) ) {
throw new Error ( ` Artifact name is not valid: ${ name } . Contains character: " ${ invalidChar } ". Invalid artifact name characters include: ${ invalidArtifactNameCharacters . toString ( ) } . ` ) ;
}
}
}
exports . checkArtifactName = checkArtifactName ;
/**
* Scans the name of the filePath used to make sure there are no illegal characters
*/
function checkArtifactFilePath ( path ) {
if ( ! path ) {
throw new Error ( ` Artifact path: ${ path } , is incorrectly provided ` ) ;
}
for ( const invalidChar of invalidArtifactFilePathCharacters ) {
if ( path . includes ( invalidChar ) ) {
throw new Error ( ` Artifact path is not valid: ${ path } . Contains character: " ${ invalidChar } ". Invalid characters include: ${ invalidArtifactFilePathCharacters . toString ( ) } . ` ) ;
}
}
}
exports . checkArtifactFilePath = checkArtifactFilePath ;
function createDirectoriesForArtifact ( directories ) {
return _ _awaiter ( this , void 0 , void 0 , function * ( ) {
for ( const directory of directories ) {
yield fs _1 . promises . mkdir ( directory , {
recursive : true
} ) ;
}
} ) ;
}
exports . createDirectoriesForArtifact = createDirectoriesForArtifact ;
function createEmptyFilesForArtifact ( emptyFilesToCreate ) {
return _ _awaiter ( this , void 0 , void 0 , function * ( ) {
for ( const filePath of emptyFilesToCreate ) {
yield ( yield fs _1 . promises . open ( filePath , 'w' ) ) . close ( ) ;
}
} ) ;
}
exports . createEmptyFilesForArtifact = createEmptyFilesForArtifact ;
function getFileSize ( filePath ) {
return _ _awaiter ( this , void 0 , void 0 , function * ( ) {
const stats = yield fs _1 . promises . stat ( filePath ) ;
core _1 . debug ( ` ${ filePath } size:( ${ stats . size } ) blksize:( ${ stats . blksize } ) blocks:( ${ stats . blocks } ) ` ) ;
return stats . size ;
} ) ;
}
exports . getFileSize = getFileSize ;
function rmFile ( filePath ) {
return _ _awaiter ( this , void 0 , void 0 , function * ( ) {
yield fs _1 . promises . unlink ( filePath ) ;
} ) ;
}
exports . rmFile = rmFile ;
function getProperRetention ( retentionInput , retentionSetting ) {
if ( retentionInput < 0 ) {
throw new Error ( 'Invalid retention, minimum value is 1.' ) ;
}
let retention = retentionInput ;
if ( retentionSetting ) {
const maxRetention = parseInt ( retentionSetting ) ;
if ( ! isNaN ( maxRetention ) && maxRetention < retention ) {
core _1 . warning ( ` Retention days is greater than the max value allowed by the repository setting, reduce retention to ${ maxRetention } days ` ) ;
retention = maxRetention ;
}
}
return retention ;
}
exports . getProperRetention = getProperRetention ;
function sleep ( milliseconds ) {
return _ _awaiter ( this , void 0 , void 0 , function * ( ) {
return new Promise ( resolve => setTimeout ( resolve , milliseconds ) ) ;
} ) ;
}
exports . sleep = sleep ;
//# sourceMappingURL=utils.js.map