2022-07-12 09:00:22 +02: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 ( ) ) ;
} ) ;
} ;
var _ _importStar = ( this && this . _ _importStar ) || function ( mod ) {
if ( mod && mod . _ _esModule ) return mod ;
var result = { } ;
if ( mod != null ) for ( var k in mod ) if ( Object . hasOwnProperty . call ( mod , k ) ) result [ k ] = mod [ k ] ;
result [ "default" ] = mod ;
return result ;
} ;
Object . defineProperty ( exports , "__esModule" , { value : true } ) ;
const core = _ _importStar ( require ( "@actions/core" ) ) ;
const http _client _1 = require ( "@actions/http-client" ) ;
const auth _1 = require ( "@actions/http-client/lib/auth" ) ;
const crypto = _ _importStar ( require ( "crypto" ) ) ;
const fs = _ _importStar ( require ( "fs" ) ) ;
const url _1 = require ( "url" ) ;
const utils = _ _importStar ( require ( "./cacheUtils" ) ) ;
const downloadUtils _1 = require ( "./downloadUtils" ) ;
const options _1 = require ( "../options" ) ;
const requestUtils _1 = require ( "./requestUtils" ) ;
const versionSalt = '1.0' ;
function getCacheApiUrl ( resource ) {
const baseUrl = process . env [ 'ACTIONS_CACHE_URL' ] || '' ;
if ( ! baseUrl ) {
throw new Error ( 'Cache Service Url not found, unable to restore cache.' ) ;
}
const url = ` ${ baseUrl } _apis/artifactcache/ ${ resource } ` ;
core . debug ( ` Resource Url: ${ url } ` ) ;
return url ;
}
function createAcceptHeader ( type , apiVersion ) {
return ` ${ type } ;api-version= ${ apiVersion } ` ;
}
function getRequestOptions ( ) {
const requestOptions = {
headers : {
Accept : createAcceptHeader ( 'application/json' , '6.0-preview.1' )
}
} ;
return requestOptions ;
}
function createHttpClient ( ) {
const token = process . env [ 'ACTIONS_RUNTIME_TOKEN' ] || '' ;
const bearerCredentialHandler = new auth _1 . BearerCredentialHandler ( token ) ;
return new http _client _1 . HttpClient ( 'actions/cache' , [ bearerCredentialHandler ] , getRequestOptions ( ) ) ;
}
2023-02-22 17:47:24 -08:00
function getCacheVersion ( paths , compressionMethod , enableCrossOsArchive = false ) {
const components = paths ;
// Add compression method to cache version to restore
// compressed cache as per compression method
if ( compressionMethod ) {
components . push ( compressionMethod ) ;
}
// Only check for windows platforms if enableCrossOsArchive is false
if ( process . platform === 'win32' && ! enableCrossOsArchive ) {
components . push ( 'windows-only' ) ;
}
2022-07-12 09:00:22 +02:00
// Add salt to cache version to support breaking changes in cache entry
components . push ( versionSalt ) ;
return crypto
. createHash ( 'sha256' )
. update ( components . join ( '|' ) )
. digest ( 'hex' ) ;
}
exports . getCacheVersion = getCacheVersion ;
function getCacheEntry ( keys , paths , options ) {
return _ _awaiter ( this , void 0 , void 0 , function * ( ) {
const httpClient = createHttpClient ( ) ;
2023-02-22 17:47:24 -08:00
const version = getCacheVersion ( paths , options === null || options === void 0 ? void 0 : options . compressionMethod , options === null || options === void 0 ? void 0 : options . enableCrossOsArchive ) ;
2022-07-12 09:00:22 +02:00
const resource = ` cache?keys= ${ encodeURIComponent ( keys . join ( ',' ) ) } &version= ${ version } ` ;
const response = yield requestUtils _1 . retryTypedResponse ( 'getCacheEntry' , ( ) => _ _awaiter ( this , void 0 , void 0 , function * ( ) { return httpClient . getJson ( getCacheApiUrl ( resource ) ) ; } ) ) ;
2023-02-22 17:47:24 -08:00
// Cache not found
2022-07-12 09:00:22 +02:00
if ( response . statusCode === 204 ) {
2023-02-22 17:47:24 -08:00
// List cache for primary key only if cache miss occurs
if ( core . isDebug ( ) ) {
yield printCachesListForDiagnostics ( keys [ 0 ] , httpClient , version ) ;
}
2022-07-12 09:00:22 +02:00
return null ;
}
if ( ! requestUtils _1 . isSuccessStatusCode ( response . statusCode ) ) {
throw new Error ( ` Cache service responded with ${ response . statusCode } ` ) ;
}
const cacheResult = response . result ;
const cacheDownloadUrl = cacheResult === null || cacheResult === void 0 ? void 0 : cacheResult . archiveLocation ;
if ( ! cacheDownloadUrl ) {
2023-02-22 17:47:24 -08:00
// Cache achiveLocation not found. This should never happen, and hence bail out.
2022-07-12 09:00:22 +02:00
throw new Error ( 'Cache not found.' ) ;
}
core . setSecret ( cacheDownloadUrl ) ;
core . debug ( ` Cache Result: ` ) ;
core . debug ( JSON . stringify ( cacheResult ) ) ;
return cacheResult ;
} ) ;
}
exports . getCacheEntry = getCacheEntry ;
2023-02-22 17:47:24 -08:00
function printCachesListForDiagnostics ( key , httpClient , version ) {
return _ _awaiter ( this , void 0 , void 0 , function * ( ) {
const resource = ` caches?key= ${ encodeURIComponent ( key ) } ` ;
const response = yield requestUtils _1 . retryTypedResponse ( 'listCache' , ( ) => _ _awaiter ( this , void 0 , void 0 , function * ( ) { return httpClient . getJson ( getCacheApiUrl ( resource ) ) ; } ) ) ;
if ( response . statusCode === 200 ) {
const cacheListResult = response . result ;
const totalCount = cacheListResult === null || cacheListResult === void 0 ? void 0 : cacheListResult . totalCount ;
if ( totalCount && totalCount > 0 ) {
core . debug ( ` No matching cache found for cache key ' ${ key } ', version ' ${ version } and scope ${ process . env [ 'GITHUB_REF' ] } . There exist one or more cache(s) with similar key but they have different version or scope. See more info on cache matching here: https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#matching-a-cache-key \n Other caches with similar key: ` ) ;
for ( const cacheEntry of ( cacheListResult === null || cacheListResult === void 0 ? void 0 : cacheListResult . artifactCaches ) || [ ] ) {
core . debug ( ` Cache Key: ${ cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry . cacheKey } , Cache Version: ${ cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry . cacheVersion } , Cache Scope: ${ cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry . scope } , Cache Created: ${ cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry . creationTime } ` ) ;
}
}
}
} ) ;
}
2022-07-12 09:00:22 +02:00
function downloadCache ( archiveLocation , archivePath , options ) {
return _ _awaiter ( this , void 0 , void 0 , function * ( ) {
const archiveUrl = new url _1 . URL ( archiveLocation ) ;
const downloadOptions = options _1 . getDownloadOptions ( options ) ;
if ( downloadOptions . useAzureSdk &&
archiveUrl . hostname . endsWith ( '.blob.core.windows.net' ) ) {
// Use Azure storage SDK to download caches hosted on Azure to improve speed and reliability.
yield downloadUtils _1 . downloadCacheStorageSDK ( archiveLocation , archivePath , downloadOptions ) ;
}
else {
// Otherwise, download using the Actions http-client.
yield downloadUtils _1 . downloadCacheHttpClient ( archiveLocation , archivePath ) ;
}
} ) ;
}
exports . downloadCache = downloadCache ;
// Reserve Cache
function reserveCache ( key , paths , options ) {
return _ _awaiter ( this , void 0 , void 0 , function * ( ) {
const httpClient = createHttpClient ( ) ;
2023-02-22 17:47:24 -08:00
const version = getCacheVersion ( paths , options === null || options === void 0 ? void 0 : options . compressionMethod , options === null || options === void 0 ? void 0 : options . enableCrossOsArchive ) ;
2022-07-12 09:00:22 +02:00
const reserveCacheRequest = {
key ,
version ,
cacheSize : options === null || options === void 0 ? void 0 : options . cacheSize
} ;
const response = yield requestUtils _1 . retryTypedResponse ( 'reserveCache' , ( ) => _ _awaiter ( this , void 0 , void 0 , function * ( ) {
return httpClient . postJson ( getCacheApiUrl ( 'caches' ) , reserveCacheRequest ) ;
} ) ) ;
return response ;
} ) ;
}
exports . reserveCache = reserveCache ;
function getContentRange ( start , end ) {
// Format: `bytes start-end/filesize
// start and end are inclusive
// filesize can be *
// For a 200 byte chunk starting at byte 0:
// Content-Range: bytes 0-199/*
return ` bytes ${ start } - ${ end } /* ` ;
}
function uploadChunk ( httpClient , resourceUrl , openStream , start , end ) {
return _ _awaiter ( this , void 0 , void 0 , function * ( ) {
core . debug ( ` Uploading chunk of size ${ end -
start +
1 } bytes at offset $ { start } with content range : $ { getContentRange ( start , end ) } ` );
const additionalHeaders = {
'Content-Type' : 'application/octet-stream' ,
'Content-Range' : getContentRange ( start , end )
} ;
const uploadChunkResponse = yield requestUtils _1 . retryHttpClientResponse ( ` uploadChunk (start: ${ start } , end: ${ end } ) ` , ( ) => _ _awaiter ( this , void 0 , void 0 , function * ( ) {
return httpClient . sendStream ( 'PATCH' , resourceUrl , openStream ( ) , additionalHeaders ) ;
} ) ) ;
if ( ! requestUtils _1 . isSuccessStatusCode ( uploadChunkResponse . message . statusCode ) ) {
throw new Error ( ` Cache service responded with ${ uploadChunkResponse . message . statusCode } during upload chunk. ` ) ;
}
} ) ;
}
function uploadFile ( httpClient , cacheId , archivePath , options ) {
return _ _awaiter ( this , void 0 , void 0 , function * ( ) {
// Upload Chunks
const fileSize = utils . getArchiveFileSizeInBytes ( archivePath ) ;
const resourceUrl = getCacheApiUrl ( ` caches/ ${ cacheId . toString ( ) } ` ) ;
const fd = fs . openSync ( archivePath , 'r' ) ;
const uploadOptions = options _1 . getUploadOptions ( options ) ;
const concurrency = utils . assertDefined ( 'uploadConcurrency' , uploadOptions . uploadConcurrency ) ;
const maxChunkSize = utils . assertDefined ( 'uploadChunkSize' , uploadOptions . uploadChunkSize ) ;
const parallelUploads = [ ... new Array ( concurrency ) . keys ( ) ] ;
core . debug ( 'Awaiting all uploads' ) ;
let offset = 0 ;
try {
yield Promise . all ( parallelUploads . map ( ( ) => _ _awaiter ( this , void 0 , void 0 , function * ( ) {
while ( offset < fileSize ) {
const chunkSize = Math . min ( fileSize - offset , maxChunkSize ) ;
const start = offset ;
const end = offset + chunkSize - 1 ;
offset += maxChunkSize ;
yield uploadChunk ( httpClient , resourceUrl , ( ) => fs
. createReadStream ( archivePath , {
fd ,
start ,
end ,
autoClose : false
} )
. on ( 'error' , error => {
throw new Error ( ` Cache upload failed because file read failed with ${ error . message } ` ) ;
} ) , start , end ) ;
}
} ) ) ) ;
}
finally {
fs . closeSync ( fd ) ;
}
return ;
} ) ;
}
function commitCache ( httpClient , cacheId , filesize ) {
return _ _awaiter ( this , void 0 , void 0 , function * ( ) {
const commitCacheRequest = { size : filesize } ;
return yield requestUtils _1 . retryTypedResponse ( 'commitCache' , ( ) => _ _awaiter ( this , void 0 , void 0 , function * ( ) {
return httpClient . postJson ( getCacheApiUrl ( ` caches/ ${ cacheId . toString ( ) } ` ) , commitCacheRequest ) ;
} ) ) ;
} ) ;
}
function saveCache ( cacheId , archivePath , options ) {
return _ _awaiter ( this , void 0 , void 0 , function * ( ) {
const httpClient = createHttpClient ( ) ;
core . debug ( 'Upload cache' ) ;
yield uploadFile ( httpClient , cacheId , archivePath , options ) ;
// Commit Cache
core . debug ( 'Commiting cache' ) ;
const cacheSize = utils . getArchiveFileSizeInBytes ( archivePath ) ;
core . info ( ` Cache Size: ~ ${ Math . round ( cacheSize / ( 1024 * 1024 ) ) } MB ( ${ cacheSize } B) ` ) ;
const commitCacheResponse = yield commitCache ( httpClient , cacheId , cacheSize ) ;
if ( ! requestUtils _1 . isSuccessStatusCode ( commitCacheResponse . statusCode ) ) {
throw new Error ( ` Cache service responded with ${ commitCacheResponse . statusCode } during commit cache. ` ) ;
}
core . info ( 'Cache saved successfully' ) ;
} ) ;
}
exports . saveCache = saveCache ;
//# sourceMappingURL=cacheHttpClient.js.map