Basic implementation

This commit is contained in:
Sankalp Kotewar 2022-11-25 09:16:56 +00:00 committed by GitHub
parent 6babf202a4
commit 69b8227b27
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 320 additions and 174 deletions

View File

@ -0,0 +1,14 @@
{
"name": "Node.js & TypeScript",
"image": "mcr.microsoft.com/devcontainers/typescript-node:16-bullseye",
// Features to add to the dev container. More info: https://containers.dev/implementors/features.
// "features": {},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "npm install && npm run build"
// Configure tool-specific properties.
// "customizations": {},
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}

View File

@ -14,6 +14,14 @@ inputs:
upload-chunk-size: upload-chunk-size:
description: 'The chunk size used to split up large files during upload, in bytes' description: 'The chunk size used to split up large files during upload, in bytes'
required: false required: false
exit-on-cache-miss:
description: 'Fail the workflow if the cache is not found for the primary key'
required: false
default: false
save-on-any-failure:
description: 'Save cache (on cache miss) despite of any failure during the workflow run'
required: false
default: false
outputs: outputs:
cache-hit: cache-hit:
description: 'A boolean value to indicate an exact match was found for the primary key' description: 'A boolean value to indicate an exact match was found for the primary key'
@ -21,7 +29,7 @@ runs:
using: 'node16' using: 'node16'
main: 'dist/restore/index.js' main: 'dist/restore/index.js'
post: 'dist/save/index.js' post: 'dist/save/index.js'
post-if: 'success()' post-if: (success() || (env.SAVE_CACHE_ON_ANY_FAILURE == 'yes'))
branding: branding:
icon: 'archive' icon: 'archive'
color: 'gray-dark' color: 'gray-dark'

183
dist/restore/index.js vendored
View File

@ -1892,10 +1892,10 @@ function serial(list, iterator, callback)
module.exports = minimatch module.exports = minimatch
minimatch.Minimatch = Minimatch minimatch.Minimatch = Minimatch
var path = { sep: '/' } var path = (function () { try { return __webpack_require__(622) } catch (e) {}}()) || {
try { sep: '/'
path = __webpack_require__(622) }
} catch (er) {} minimatch.sep = path.sep
var GLOBSTAR = minimatch.GLOBSTAR = Minimatch.GLOBSTAR = {} var GLOBSTAR = minimatch.GLOBSTAR = Minimatch.GLOBSTAR = {}
var expand = __webpack_require__(306) var expand = __webpack_require__(306)
@ -1947,43 +1947,64 @@ function filter (pattern, options) {
} }
function ext (a, b) { function ext (a, b) {
a = a || {}
b = b || {} b = b || {}
var t = {} var t = {}
Object.keys(b).forEach(function (k) {
t[k] = b[k]
})
Object.keys(a).forEach(function (k) { Object.keys(a).forEach(function (k) {
t[k] = a[k] t[k] = a[k]
}) })
Object.keys(b).forEach(function (k) {
t[k] = b[k]
})
return t return t
} }
minimatch.defaults = function (def) { minimatch.defaults = function (def) {
if (!def || !Object.keys(def).length) return minimatch if (!def || typeof def !== 'object' || !Object.keys(def).length) {
return minimatch
}
var orig = minimatch var orig = minimatch
var m = function minimatch (p, pattern, options) { var m = function minimatch (p, pattern, options) {
return orig.minimatch(p, pattern, ext(def, options)) return orig(p, pattern, ext(def, options))
} }
m.Minimatch = function Minimatch (pattern, options) { m.Minimatch = function Minimatch (pattern, options) {
return new orig.Minimatch(pattern, ext(def, options)) return new orig.Minimatch(pattern, ext(def, options))
} }
m.Minimatch.defaults = function defaults (options) {
return orig.defaults(ext(def, options)).Minimatch
}
m.filter = function filter (pattern, options) {
return orig.filter(pattern, ext(def, options))
}
m.defaults = function defaults (options) {
return orig.defaults(ext(def, options))
}
m.makeRe = function makeRe (pattern, options) {
return orig.makeRe(pattern, ext(def, options))
}
m.braceExpand = function braceExpand (pattern, options) {
return orig.braceExpand(pattern, ext(def, options))
}
m.match = function (list, pattern, options) {
return orig.match(list, pattern, ext(def, options))
}
return m return m
} }
Minimatch.defaults = function (def) { Minimatch.defaults = function (def) {
if (!def || !Object.keys(def).length) return Minimatch
return minimatch.defaults(def).Minimatch return minimatch.defaults(def).Minimatch
} }
function minimatch (p, pattern, options) { function minimatch (p, pattern, options) {
if (typeof pattern !== 'string') { assertValidPattern(pattern)
throw new TypeError('glob pattern string required')
}
if (!options) options = {} if (!options) options = {}
@ -1992,9 +2013,6 @@ function minimatch (p, pattern, options) {
return false return false
} }
// "" only matches ""
if (pattern.trim() === '') return p === ''
return new Minimatch(pattern, options).match(p) return new Minimatch(pattern, options).match(p)
} }
@ -2003,15 +2021,14 @@ function Minimatch (pattern, options) {
return new Minimatch(pattern, options) return new Minimatch(pattern, options)
} }
if (typeof pattern !== 'string') { assertValidPattern(pattern)
throw new TypeError('glob pattern string required')
}
if (!options) options = {} if (!options) options = {}
pattern = pattern.trim() pattern = pattern.trim()
// windows support: need to use /, not \ // windows support: need to use /, not \
if (path.sep !== '/') { if (!options.allowWindowsEscape && path.sep !== '/') {
pattern = pattern.split(path.sep).join('/') pattern = pattern.split(path.sep).join('/')
} }
@ -2022,6 +2039,7 @@ function Minimatch (pattern, options) {
this.negate = false this.negate = false
this.comment = false this.comment = false
this.empty = false this.empty = false
this.partial = !!options.partial
// make the set of regexps etc. // make the set of regexps etc.
this.make() this.make()
@ -2031,9 +2049,6 @@ Minimatch.prototype.debug = function () {}
Minimatch.prototype.make = make Minimatch.prototype.make = make
function make () { function make () {
// don't do it more than once.
if (this._made) return
var pattern = this.pattern var pattern = this.pattern
var options = this.options var options = this.options
@ -2053,7 +2068,7 @@ function make () {
// step 2: expand braces // step 2: expand braces
var set = this.globSet = this.braceExpand() var set = this.globSet = this.braceExpand()
if (options.debug) this.debug = console.error if (options.debug) this.debug = function debug() { console.error.apply(console, arguments) }
this.debug(this.pattern, set) this.debug(this.pattern, set)
@ -2133,12 +2148,11 @@ function braceExpand (pattern, options) {
pattern = typeof pattern === 'undefined' pattern = typeof pattern === 'undefined'
? this.pattern : pattern ? this.pattern : pattern
if (typeof pattern === 'undefined') { assertValidPattern(pattern)
throw new TypeError('undefined pattern')
}
if (options.nobrace || // Thanks to Yeting Li <https://github.com/yetingli> for
!pattern.match(/\{.*\}/)) { // improving this regexp to avoid a ReDOS vulnerability.
if (options.nobrace || !/\{(?:(?!\{).)*\}/.test(pattern)) {
// shortcut. no need to expand. // shortcut. no need to expand.
return [pattern] return [pattern]
} }
@ -2146,6 +2160,17 @@ function braceExpand (pattern, options) {
return expand(pattern) return expand(pattern)
} }
var MAX_PATTERN_LENGTH = 1024 * 64
var assertValidPattern = function (pattern) {
if (typeof pattern !== 'string') {
throw new TypeError('invalid pattern')
}
if (pattern.length > MAX_PATTERN_LENGTH) {
throw new TypeError('pattern is too long')
}
}
// parse a component of the expanded set. // parse a component of the expanded set.
// At this point, no pattern may contain "/" in it // At this point, no pattern may contain "/" in it
// so we're going to return a 2d array, where each entry is the full // so we're going to return a 2d array, where each entry is the full
@ -2160,14 +2185,17 @@ function braceExpand (pattern, options) {
Minimatch.prototype.parse = parse Minimatch.prototype.parse = parse
var SUBPARSE = {} var SUBPARSE = {}
function parse (pattern, isSub) { function parse (pattern, isSub) {
if (pattern.length > 1024 * 64) { assertValidPattern(pattern)
throw new TypeError('pattern is too long')
}
var options = this.options var options = this.options
// shortcuts // shortcuts
if (!options.noglobstar && pattern === '**') return GLOBSTAR if (pattern === '**') {
if (!options.noglobstar)
return GLOBSTAR
else
pattern = '*'
}
if (pattern === '') return '' if (pattern === '') return ''
var re = '' var re = ''
@ -2223,10 +2251,12 @@ function parse (pattern, isSub) {
} }
switch (c) { switch (c) {
case '/': /* istanbul ignore next */
case '/': {
// completely not allowed, even escaped. // completely not allowed, even escaped.
// Should already be path-split by now. // Should already be path-split by now.
return false return false
}
case '\\': case '\\':
clearStateChar() clearStateChar()
@ -2345,25 +2375,23 @@ function parse (pattern, isSub) {
// handle the case where we left a class open. // handle the case where we left a class open.
// "[z-a]" is valid, equivalent to "\[z-a\]" // "[z-a]" is valid, equivalent to "\[z-a\]"
if (inClass) { // split where the last [ was, make sure we don't have
// split where the last [ was, make sure we don't have // an invalid re. if so, re-walk the contents of the
// an invalid re. if so, re-walk the contents of the // would-be class to re-translate any characters that
// would-be class to re-translate any characters that // were passed through as-is
// were passed through as-is // TODO: It would probably be faster to determine this
// TODO: It would probably be faster to determine this // without a try/catch and a new RegExp, but it's tricky
// without a try/catch and a new RegExp, but it's tricky // to do safely. For now, this is safe and works.
// to do safely. For now, this is safe and works. var cs = pattern.substring(classStart + 1, i)
var cs = pattern.substring(classStart + 1, i) try {
try { RegExp('[' + cs + ']')
RegExp('[' + cs + ']') } catch (er) {
} catch (er) { // not a valid class!
// not a valid class! var sp = this.parse(cs, SUBPARSE)
var sp = this.parse(cs, SUBPARSE) re = re.substr(0, reClassStart) + '\\[' + sp[0] + '\\]'
re = re.substr(0, reClassStart) + '\\[' + sp[0] + '\\]' hasMagic = hasMagic || sp[1]
hasMagic = hasMagic || sp[1] inClass = false
inClass = false continue
continue
}
} }
// finish up the class. // finish up the class.
@ -2447,9 +2475,7 @@ function parse (pattern, isSub) {
// something that could conceivably capture a dot // something that could conceivably capture a dot
var addPatternStart = false var addPatternStart = false
switch (re.charAt(0)) { switch (re.charAt(0)) {
case '.': case '[': case '.': case '(': addPatternStart = true
case '[':
case '(': addPatternStart = true
} }
// Hack to work around lack of negative lookbehind in JS // Hack to work around lack of negative lookbehind in JS
@ -2511,7 +2537,7 @@ function parse (pattern, isSub) {
var flags = options.nocase ? 'i' : '' var flags = options.nocase ? 'i' : ''
try { try {
var regExp = new RegExp('^' + re + '$', flags) var regExp = new RegExp('^' + re + '$', flags)
} catch (er) { } catch (er) /* istanbul ignore next - should be impossible */ {
// If it was an invalid regular expression, then it can't match // If it was an invalid regular expression, then it can't match
// anything. This trick looks for a character after the end of // anything. This trick looks for a character after the end of
// the string, which is of course impossible, except in multi-line // the string, which is of course impossible, except in multi-line
@ -2569,7 +2595,7 @@ function makeRe () {
try { try {
this.regexp = new RegExp(re, flags) this.regexp = new RegExp(re, flags)
} catch (ex) { } catch (ex) /* istanbul ignore next - should be impossible */ {
this.regexp = false this.regexp = false
} }
return this.regexp return this.regexp
@ -2587,8 +2613,8 @@ minimatch.match = function (list, pattern, options) {
return list return list
} }
Minimatch.prototype.match = match Minimatch.prototype.match = function match (f, partial) {
function match (f, partial) { if (typeof partial === 'undefined') partial = this.partial
this.debug('match', f, this.pattern) this.debug('match', f, this.pattern)
// short-circuit in the case of busted things. // short-circuit in the case of busted things.
// comments, etc. // comments, etc.
@ -2670,6 +2696,7 @@ Minimatch.prototype.matchOne = function (file, pattern, partial) {
// should be impossible. // should be impossible.
// some invalid regexp stuff in the set. // some invalid regexp stuff in the set.
/* istanbul ignore if */
if (p === false) return false if (p === false) return false
if (p === GLOBSTAR) { if (p === GLOBSTAR) {
@ -2743,6 +2770,7 @@ Minimatch.prototype.matchOne = function (file, pattern, partial) {
// no match was found. // no match was found.
// However, in partial mode, we can't say this is necessarily over. // However, in partial mode, we can't say this is necessarily over.
// If there's more *pattern* left, then // If there's more *pattern* left, then
/* istanbul ignore if */
if (partial) { if (partial) {
// ran out of file // ran out of file
this.debug('\n>>> no match, partial?', file, fr, pattern, pr) this.debug('\n>>> no match, partial?', file, fr, pattern, pr)
@ -2756,11 +2784,7 @@ Minimatch.prototype.matchOne = function (file, pattern, partial) {
// patterns with magic have been turned into regexps. // patterns with magic have been turned into regexps.
var hit var hit
if (typeof p === 'string') { if (typeof p === 'string') {
if (options.nocase) { hit = f === p
hit = f.toLowerCase() === p.toLowerCase()
} else {
hit = f === p
}
this.debug('string match', p, f, hit) this.debug('string match', p, f, hit)
} else { } else {
hit = f.match(p) hit = f.match(p)
@ -2791,16 +2815,16 @@ Minimatch.prototype.matchOne = function (file, pattern, partial) {
// this is ok if we're doing the match as part of // this is ok if we're doing the match as part of
// a glob fs traversal. // a glob fs traversal.
return partial return partial
} else if (pi === pl) { } else /* istanbul ignore else */ if (pi === pl) {
// ran out of pattern, still have file left. // ran out of pattern, still have file left.
// this is only acceptable if we're on the very last // this is only acceptable if we're on the very last
// empty segment of a file with a trailing slash. // empty segment of a file with a trailing slash.
// a/* should match a/b/ // a/* should match a/b/
var emptyFileEnd = (fi === fl - 1) && (file[fi] === '') return (fi === fl - 1) && (file[fi] === '')
return emptyFileEnd
} }
// should be unreachable. // should be unreachable.
/* istanbul ignore next */
throw new Error('wtf?') throw new Error('wtf?')
} }
@ -4940,13 +4964,15 @@ exports.checkBypass = checkBypass;
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.RefKey = exports.Events = exports.State = exports.Outputs = exports.Inputs = void 0; exports.RefKey = exports.Variables = exports.Events = exports.State = exports.Outputs = exports.Inputs = void 0;
var Inputs; var Inputs;
(function (Inputs) { (function (Inputs) {
Inputs["Key"] = "key"; Inputs["Key"] = "key";
Inputs["Path"] = "path"; Inputs["Path"] = "path";
Inputs["RestoreKeys"] = "restore-keys"; Inputs["RestoreKeys"] = "restore-keys";
Inputs["UploadChunkSize"] = "upload-chunk-size"; Inputs["UploadChunkSize"] = "upload-chunk-size";
Inputs["StrictRestore"] = "strict-restore";
Inputs["SaveOnAnyFailure"] = "save-on-any-failure";
})(Inputs = exports.Inputs || (exports.Inputs = {})); })(Inputs = exports.Inputs || (exports.Inputs = {}));
var Outputs; var Outputs;
(function (Outputs) { (function (Outputs) {
@ -4963,6 +4989,10 @@ var Events;
Events["Push"] = "push"; Events["Push"] = "push";
Events["PullRequest"] = "pull_request"; Events["PullRequest"] = "pull_request";
})(Events = exports.Events || (exports.Events = {})); })(Events = exports.Events || (exports.Events = {}));
var Variables;
(function (Variables) {
Variables["SaveCacheOnAnyFailure"] = "SAVE_CACHE_ON_ANY_FAILURE";
})(Variables = exports.Variables || (exports.Variables = {}));
exports.RefKey = "GITHUB_REF"; exports.RefKey = "GITHUB_REF";
@ -48984,7 +49014,17 @@ function run() {
required: true required: true
}); });
const cacheKey = yield cache.restoreCache(cachePaths, primaryKey, restoreKeys); const cacheKey = yield cache.restoreCache(cachePaths, primaryKey, restoreKeys);
//Check if user wants to save cache despite of failure in any previous job
const saveCache = core.getInput(constants_1.Inputs.SaveOnAnyFailure);
if (saveCache === "yes") {
core.debug(`save cache input variable is set to yes`);
core.exportVariable(constants_1.Variables.SaveCacheOnAnyFailure, saveCache);
core.info(`Input Variable ${constants_1.Variables.SaveCacheOnAnyFailure} is set to yes, the cache will be saved despite of any failure in the build.`);
}
if (!cacheKey) { if (!cacheKey) {
if (core.getInput(constants_1.Inputs.StrictRestore) == "yes") {
throw new Error(`Cache with the given input key ${primaryKey} is not found, hence exiting the workflow as the strict-restore requirement is not met.`);
}
core.info(`Cache not found for input keys: ${[ core.info(`Cache not found for input keys: ${[
primaryKey, primaryKey,
...restoreKeys ...restoreKeys
@ -48995,6 +49035,9 @@ function run() {
utils.setCacheState(cacheKey); utils.setCacheState(cacheKey);
const isExactKeyMatch = utils.isExactKeyMatch(primaryKey, cacheKey); const isExactKeyMatch = utils.isExactKeyMatch(primaryKey, cacheKey);
utils.setCacheHitOutput(isExactKeyMatch); utils.setCacheHitOutput(isExactKeyMatch);
if (!isExactKeyMatch && core.getInput(constants_1.Inputs.StrictRestore) == "yes") {
throw new Error(`Restored cache key doesn't match the given input key ${primaryKey}, hence exiting the workflow as the strict-restore requirement is not met.`);
}
core.info(`Cache restored from key: ${cacheKey}`); core.info(`Cache restored from key: ${cacheKey}`);
} }
catch (error) { catch (error) {

172
dist/save/index.js vendored
View File

@ -1892,10 +1892,10 @@ function serial(list, iterator, callback)
module.exports = minimatch module.exports = minimatch
minimatch.Minimatch = Minimatch minimatch.Minimatch = Minimatch
var path = { sep: '/' } var path = (function () { try { return __webpack_require__(622) } catch (e) {}}()) || {
try { sep: '/'
path = __webpack_require__(622) }
} catch (er) {} minimatch.sep = path.sep
var GLOBSTAR = minimatch.GLOBSTAR = Minimatch.GLOBSTAR = {} var GLOBSTAR = minimatch.GLOBSTAR = Minimatch.GLOBSTAR = {}
var expand = __webpack_require__(306) var expand = __webpack_require__(306)
@ -1947,43 +1947,64 @@ function filter (pattern, options) {
} }
function ext (a, b) { function ext (a, b) {
a = a || {}
b = b || {} b = b || {}
var t = {} var t = {}
Object.keys(b).forEach(function (k) {
t[k] = b[k]
})
Object.keys(a).forEach(function (k) { Object.keys(a).forEach(function (k) {
t[k] = a[k] t[k] = a[k]
}) })
Object.keys(b).forEach(function (k) {
t[k] = b[k]
})
return t return t
} }
minimatch.defaults = function (def) { minimatch.defaults = function (def) {
if (!def || !Object.keys(def).length) return minimatch if (!def || typeof def !== 'object' || !Object.keys(def).length) {
return minimatch
}
var orig = minimatch var orig = minimatch
var m = function minimatch (p, pattern, options) { var m = function minimatch (p, pattern, options) {
return orig.minimatch(p, pattern, ext(def, options)) return orig(p, pattern, ext(def, options))
} }
m.Minimatch = function Minimatch (pattern, options) { m.Minimatch = function Minimatch (pattern, options) {
return new orig.Minimatch(pattern, ext(def, options)) return new orig.Minimatch(pattern, ext(def, options))
} }
m.Minimatch.defaults = function defaults (options) {
return orig.defaults(ext(def, options)).Minimatch
}
m.filter = function filter (pattern, options) {
return orig.filter(pattern, ext(def, options))
}
m.defaults = function defaults (options) {
return orig.defaults(ext(def, options))
}
m.makeRe = function makeRe (pattern, options) {
return orig.makeRe(pattern, ext(def, options))
}
m.braceExpand = function braceExpand (pattern, options) {
return orig.braceExpand(pattern, ext(def, options))
}
m.match = function (list, pattern, options) {
return orig.match(list, pattern, ext(def, options))
}
return m return m
} }
Minimatch.defaults = function (def) { Minimatch.defaults = function (def) {
if (!def || !Object.keys(def).length) return Minimatch
return minimatch.defaults(def).Minimatch return minimatch.defaults(def).Minimatch
} }
function minimatch (p, pattern, options) { function minimatch (p, pattern, options) {
if (typeof pattern !== 'string') { assertValidPattern(pattern)
throw new TypeError('glob pattern string required')
}
if (!options) options = {} if (!options) options = {}
@ -1992,9 +2013,6 @@ function minimatch (p, pattern, options) {
return false return false
} }
// "" only matches ""
if (pattern.trim() === '') return p === ''
return new Minimatch(pattern, options).match(p) return new Minimatch(pattern, options).match(p)
} }
@ -2003,15 +2021,14 @@ function Minimatch (pattern, options) {
return new Minimatch(pattern, options) return new Minimatch(pattern, options)
} }
if (typeof pattern !== 'string') { assertValidPattern(pattern)
throw new TypeError('glob pattern string required')
}
if (!options) options = {} if (!options) options = {}
pattern = pattern.trim() pattern = pattern.trim()
// windows support: need to use /, not \ // windows support: need to use /, not \
if (path.sep !== '/') { if (!options.allowWindowsEscape && path.sep !== '/') {
pattern = pattern.split(path.sep).join('/') pattern = pattern.split(path.sep).join('/')
} }
@ -2022,6 +2039,7 @@ function Minimatch (pattern, options) {
this.negate = false this.negate = false
this.comment = false this.comment = false
this.empty = false this.empty = false
this.partial = !!options.partial
// make the set of regexps etc. // make the set of regexps etc.
this.make() this.make()
@ -2031,9 +2049,6 @@ Minimatch.prototype.debug = function () {}
Minimatch.prototype.make = make Minimatch.prototype.make = make
function make () { function make () {
// don't do it more than once.
if (this._made) return
var pattern = this.pattern var pattern = this.pattern
var options = this.options var options = this.options
@ -2053,7 +2068,7 @@ function make () {
// step 2: expand braces // step 2: expand braces
var set = this.globSet = this.braceExpand() var set = this.globSet = this.braceExpand()
if (options.debug) this.debug = console.error if (options.debug) this.debug = function debug() { console.error.apply(console, arguments) }
this.debug(this.pattern, set) this.debug(this.pattern, set)
@ -2133,12 +2148,11 @@ function braceExpand (pattern, options) {
pattern = typeof pattern === 'undefined' pattern = typeof pattern === 'undefined'
? this.pattern : pattern ? this.pattern : pattern
if (typeof pattern === 'undefined') { assertValidPattern(pattern)
throw new TypeError('undefined pattern')
}
if (options.nobrace || // Thanks to Yeting Li <https://github.com/yetingli> for
!pattern.match(/\{.*\}/)) { // improving this regexp to avoid a ReDOS vulnerability.
if (options.nobrace || !/\{(?:(?!\{).)*\}/.test(pattern)) {
// shortcut. no need to expand. // shortcut. no need to expand.
return [pattern] return [pattern]
} }
@ -2146,6 +2160,17 @@ function braceExpand (pattern, options) {
return expand(pattern) return expand(pattern)
} }
var MAX_PATTERN_LENGTH = 1024 * 64
var assertValidPattern = function (pattern) {
if (typeof pattern !== 'string') {
throw new TypeError('invalid pattern')
}
if (pattern.length > MAX_PATTERN_LENGTH) {
throw new TypeError('pattern is too long')
}
}
// parse a component of the expanded set. // parse a component of the expanded set.
// At this point, no pattern may contain "/" in it // At this point, no pattern may contain "/" in it
// so we're going to return a 2d array, where each entry is the full // so we're going to return a 2d array, where each entry is the full
@ -2160,14 +2185,17 @@ function braceExpand (pattern, options) {
Minimatch.prototype.parse = parse Minimatch.prototype.parse = parse
var SUBPARSE = {} var SUBPARSE = {}
function parse (pattern, isSub) { function parse (pattern, isSub) {
if (pattern.length > 1024 * 64) { assertValidPattern(pattern)
throw new TypeError('pattern is too long')
}
var options = this.options var options = this.options
// shortcuts // shortcuts
if (!options.noglobstar && pattern === '**') return GLOBSTAR if (pattern === '**') {
if (!options.noglobstar)
return GLOBSTAR
else
pattern = '*'
}
if (pattern === '') return '' if (pattern === '') return ''
var re = '' var re = ''
@ -2223,10 +2251,12 @@ function parse (pattern, isSub) {
} }
switch (c) { switch (c) {
case '/': /* istanbul ignore next */
case '/': {
// completely not allowed, even escaped. // completely not allowed, even escaped.
// Should already be path-split by now. // Should already be path-split by now.
return false return false
}
case '\\': case '\\':
clearStateChar() clearStateChar()
@ -2345,25 +2375,23 @@ function parse (pattern, isSub) {
// handle the case where we left a class open. // handle the case where we left a class open.
// "[z-a]" is valid, equivalent to "\[z-a\]" // "[z-a]" is valid, equivalent to "\[z-a\]"
if (inClass) { // split where the last [ was, make sure we don't have
// split where the last [ was, make sure we don't have // an invalid re. if so, re-walk the contents of the
// an invalid re. if so, re-walk the contents of the // would-be class to re-translate any characters that
// would-be class to re-translate any characters that // were passed through as-is
// were passed through as-is // TODO: It would probably be faster to determine this
// TODO: It would probably be faster to determine this // without a try/catch and a new RegExp, but it's tricky
// without a try/catch and a new RegExp, but it's tricky // to do safely. For now, this is safe and works.
// to do safely. For now, this is safe and works. var cs = pattern.substring(classStart + 1, i)
var cs = pattern.substring(classStart + 1, i) try {
try { RegExp('[' + cs + ']')
RegExp('[' + cs + ']') } catch (er) {
} catch (er) { // not a valid class!
// not a valid class! var sp = this.parse(cs, SUBPARSE)
var sp = this.parse(cs, SUBPARSE) re = re.substr(0, reClassStart) + '\\[' + sp[0] + '\\]'
re = re.substr(0, reClassStart) + '\\[' + sp[0] + '\\]' hasMagic = hasMagic || sp[1]
hasMagic = hasMagic || sp[1] inClass = false
inClass = false continue
continue
}
} }
// finish up the class. // finish up the class.
@ -2447,9 +2475,7 @@ function parse (pattern, isSub) {
// something that could conceivably capture a dot // something that could conceivably capture a dot
var addPatternStart = false var addPatternStart = false
switch (re.charAt(0)) { switch (re.charAt(0)) {
case '.': case '[': case '.': case '(': addPatternStart = true
case '[':
case '(': addPatternStart = true
} }
// Hack to work around lack of negative lookbehind in JS // Hack to work around lack of negative lookbehind in JS
@ -2511,7 +2537,7 @@ function parse (pattern, isSub) {
var flags = options.nocase ? 'i' : '' var flags = options.nocase ? 'i' : ''
try { try {
var regExp = new RegExp('^' + re + '$', flags) var regExp = new RegExp('^' + re + '$', flags)
} catch (er) { } catch (er) /* istanbul ignore next - should be impossible */ {
// If it was an invalid regular expression, then it can't match // If it was an invalid regular expression, then it can't match
// anything. This trick looks for a character after the end of // anything. This trick looks for a character after the end of
// the string, which is of course impossible, except in multi-line // the string, which is of course impossible, except in multi-line
@ -2569,7 +2595,7 @@ function makeRe () {
try { try {
this.regexp = new RegExp(re, flags) this.regexp = new RegExp(re, flags)
} catch (ex) { } catch (ex) /* istanbul ignore next - should be impossible */ {
this.regexp = false this.regexp = false
} }
return this.regexp return this.regexp
@ -2587,8 +2613,8 @@ minimatch.match = function (list, pattern, options) {
return list return list
} }
Minimatch.prototype.match = match Minimatch.prototype.match = function match (f, partial) {
function match (f, partial) { if (typeof partial === 'undefined') partial = this.partial
this.debug('match', f, this.pattern) this.debug('match', f, this.pattern)
// short-circuit in the case of busted things. // short-circuit in the case of busted things.
// comments, etc. // comments, etc.
@ -2670,6 +2696,7 @@ Minimatch.prototype.matchOne = function (file, pattern, partial) {
// should be impossible. // should be impossible.
// some invalid regexp stuff in the set. // some invalid regexp stuff in the set.
/* istanbul ignore if */
if (p === false) return false if (p === false) return false
if (p === GLOBSTAR) { if (p === GLOBSTAR) {
@ -2743,6 +2770,7 @@ Minimatch.prototype.matchOne = function (file, pattern, partial) {
// no match was found. // no match was found.
// However, in partial mode, we can't say this is necessarily over. // However, in partial mode, we can't say this is necessarily over.
// If there's more *pattern* left, then // If there's more *pattern* left, then
/* istanbul ignore if */
if (partial) { if (partial) {
// ran out of file // ran out of file
this.debug('\n>>> no match, partial?', file, fr, pattern, pr) this.debug('\n>>> no match, partial?', file, fr, pattern, pr)
@ -2756,11 +2784,7 @@ Minimatch.prototype.matchOne = function (file, pattern, partial) {
// patterns with magic have been turned into regexps. // patterns with magic have been turned into regexps.
var hit var hit
if (typeof p === 'string') { if (typeof p === 'string') {
if (options.nocase) { hit = f === p
hit = f.toLowerCase() === p.toLowerCase()
} else {
hit = f === p
}
this.debug('string match', p, f, hit) this.debug('string match', p, f, hit)
} else { } else {
hit = f.match(p) hit = f.match(p)
@ -2791,16 +2815,16 @@ Minimatch.prototype.matchOne = function (file, pattern, partial) {
// this is ok if we're doing the match as part of // this is ok if we're doing the match as part of
// a glob fs traversal. // a glob fs traversal.
return partial return partial
} else if (pi === pl) { } else /* istanbul ignore else */ if (pi === pl) {
// ran out of pattern, still have file left. // ran out of pattern, still have file left.
// this is only acceptable if we're on the very last // this is only acceptable if we're on the very last
// empty segment of a file with a trailing slash. // empty segment of a file with a trailing slash.
// a/* should match a/b/ // a/* should match a/b/
var emptyFileEnd = (fi === fl - 1) && (file[fi] === '') return (fi === fl - 1) && (file[fi] === '')
return emptyFileEnd
} }
// should be unreachable. // should be unreachable.
/* istanbul ignore next */
throw new Error('wtf?') throw new Error('wtf?')
} }
@ -4940,13 +4964,15 @@ exports.checkBypass = checkBypass;
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.RefKey = exports.Events = exports.State = exports.Outputs = exports.Inputs = void 0; exports.RefKey = exports.Variables = exports.Events = exports.State = exports.Outputs = exports.Inputs = void 0;
var Inputs; var Inputs;
(function (Inputs) { (function (Inputs) {
Inputs["Key"] = "key"; Inputs["Key"] = "key";
Inputs["Path"] = "path"; Inputs["Path"] = "path";
Inputs["RestoreKeys"] = "restore-keys"; Inputs["RestoreKeys"] = "restore-keys";
Inputs["UploadChunkSize"] = "upload-chunk-size"; Inputs["UploadChunkSize"] = "upload-chunk-size";
Inputs["StrictRestore"] = "strict-restore";
Inputs["SaveOnAnyFailure"] = "save-on-any-failure";
})(Inputs = exports.Inputs || (exports.Inputs = {})); })(Inputs = exports.Inputs || (exports.Inputs = {}));
var Outputs; var Outputs;
(function (Outputs) { (function (Outputs) {
@ -4963,6 +4989,10 @@ var Events;
Events["Push"] = "push"; Events["Push"] = "push";
Events["PullRequest"] = "pull_request"; Events["PullRequest"] = "pull_request";
})(Events = exports.Events || (exports.Events = {})); })(Events = exports.Events || (exports.Events = {}));
var Variables;
(function (Variables) {
Variables["SaveCacheOnAnyFailure"] = "SAVE_CACHE_ON_ANY_FAILURE";
})(Variables = exports.Variables || (exports.Variables = {}));
exports.RefKey = "GITHUB_REF"; exports.RefKey = "GITHUB_REF";
@ -47298,7 +47328,7 @@ function run() {
} }
const state = utils.getCacheState(); const state = utils.getCacheState();
// Inputs are re-evaluted before the post action, so we want the original key used for restore // Inputs are re-evaluted before the post action, so we want the original key used for restore
const primaryKey = core.getState(constants_1.State.CachePrimaryKey); const primaryKey = core.getState(constants_1.State.CachePrimaryKey) || core.getInput(constants_1.Inputs.Key);
if (!primaryKey) { if (!primaryKey) {
utils.logWarning(`Error retrieving key from state.`); utils.logWarning(`Error retrieving key from state.`);
return; return;

33
package-lock.json generated
View File

@ -4055,18 +4055,6 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/eslint-plugin-import/node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/eslint-plugin-import/node_modules/ms": { "node_modules/eslint-plugin-import/node_modules/ms": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
@ -8129,9 +8117,9 @@
} }
}, },
"node_modules/minimatch": { "node_modules/minimatch": {
"version": "3.0.4", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dependencies": { "dependencies": {
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
}, },
@ -12754,15 +12742,6 @@
"has": "^1.0.3" "has": "^1.0.3"
} }
}, },
"minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"requires": {
"brace-expansion": "^1.1.7"
}
},
"ms": { "ms": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
@ -15888,9 +15867,9 @@
"dev": true "dev": true
}, },
"minimatch": { "minimatch": {
"version": "3.0.4", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"requires": { "requires": {
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
} }

26
restore/action.yml Normal file
View File

@ -0,0 +1,26 @@
name: 'Restore Cache'
description: 'Restore Cache artifacts like dependencies and build outputs to improve workflow execution time'
author: 'GitHub'
inputs:
path:
description: 'A list of files, directories, and wildcard patterns to cache and restore'
required: true
key:
description: 'An explicit key for restoring and saving the cache'
required: true
restore-keys:
description: 'An ordered list of keys to use for restoring stale cache if no cache hit occurred for key. Note `cache-hit` returns false in this case.'
required: false
strict-restore:
description: 'Fail the workflow if the cache is not found for the given key.'
required: false
default: "no"
outputs:
cache-hit:
description: 'A boolean value to indicate an exact match was found for the primary key'
runs:
using: 'node16'
main: '../dist/restore/index.js'
branding:
icon: 'archive'
color: 'gray-dark'

19
save/action.yml Normal file
View File

@ -0,0 +1,19 @@
name: 'Save Cache'
description: 'Save Cache artifacts like dependencies and build outputs to improve workflow execution time'
author: 'GitHub'
inputs:
path:
description: 'A list of files, directories, and wildcard patterns to cache and restore'
required: true
key:
description: 'An explicit key for restoring and saving the cache'
required: true
upload-chunk-size:
description: 'The chunk size used to split up large files during upload, in bytes'
required: false
runs:
using: 'node16'
main: '../dist/save/index.js'
branding:
icon: 'archive'
color: 'gray-dark'

View File

@ -2,7 +2,9 @@ export enum Inputs {
Key = "key", Key = "key",
Path = "path", Path = "path",
RestoreKeys = "restore-keys", RestoreKeys = "restore-keys",
UploadChunkSize = "upload-chunk-size" UploadChunkSize = "upload-chunk-size",
StrictRestore = "strict-restore",
SaveOnAnyFailure = "save-on-any-failure"
} }
export enum Outputs { export enum Outputs {
@ -20,4 +22,8 @@ export enum Events {
PullRequest = "pull_request" PullRequest = "pull_request"
} }
export enum Variables {
SaveCacheOnAnyFailure = "SAVE_CACHE_ON_ANY_FAILURE"
}
export const RefKey = "GITHUB_REF"; export const RefKey = "GITHUB_REF";

View File

@ -1,7 +1,7 @@
import * as cache from "@actions/cache"; import * as cache from "@actions/cache";
import * as core from "@actions/core"; import * as core from "@actions/core";
import { Events, Inputs, State } from "./constants"; import { Events, Inputs, State, Variables } from "./constants";
import * as utils from "./utils/actionUtils"; import * as utils from "./utils/actionUtils";
async function run(): Promise<void> { async function run(): Promise<void> {
@ -35,22 +35,41 @@ async function run(): Promise<void> {
restoreKeys restoreKeys
); );
//Check if user wants to save cache despite of failure in any previous job
const saveCache = core.getInput(Inputs.SaveOnAnyFailure);
if (saveCache === "yes") {
core.debug(`save cache input variable is set to yes`);
core.exportVariable(Variables.SaveCacheOnAnyFailure, saveCache);
core.info(
`Input Variable ${Variables.SaveCacheOnAnyFailure} is set to yes, the cache will be saved despite of any failure in the build.`
);
}
if (!cacheKey) { if (!cacheKey) {
if (core.getInput(Inputs.StrictRestore) == "yes") {
throw new Error(
`Cache with the given input key ${primaryKey} is not found, hence exiting the workflow as the strict-restore requirement is not met.`
);
}
core.info( core.info(
`Cache not found for input keys: ${[ `Cache not found for input keys: ${[
primaryKey, primaryKey,
...restoreKeys ...restoreKeys
].join(", ")}` ].join(", ")}`
); );
return; return;
} }
// Store the matched cache key // Store the matched cache key
utils.setCacheState(cacheKey); utils.setCacheState(cacheKey);
const isExactKeyMatch = utils.isExactKeyMatch(primaryKey, cacheKey); const isExactKeyMatch = utils.isExactKeyMatch(primaryKey, cacheKey);
utils.setCacheHitOutput(isExactKeyMatch); utils.setCacheHitOutput(isExactKeyMatch);
if (!isExactKeyMatch && core.getInput(Inputs.StrictRestore) == "yes") {
throw new Error(
`Restored cache key doesn't match the given input key ${primaryKey}, hence exiting the workflow as the strict-restore requirement is not met.`
);
}
core.info(`Cache restored from key: ${cacheKey}`); core.info(`Cache restored from key: ${cacheKey}`);
} catch (error: unknown) { } catch (error: unknown) {
core.setFailed((error as Error).message); core.setFailed((error as Error).message);

View File

@ -27,7 +27,9 @@ async function run(): Promise<void> {
const state = utils.getCacheState(); const state = utils.getCacheState();
// Inputs are re-evaluted before the post action, so we want the original key used for restore // Inputs are re-evaluted before the post action, so we want the original key used for restore
const primaryKey = core.getState(State.CachePrimaryKey); const primaryKey =
core.getState(State.CachePrimaryKey) || core.getInput(Inputs.Key);
if (!primaryKey) { if (!primaryKey) {
utils.logWarning(`Error retrieving key from state.`); utils.logWarning(`Error retrieving key from state.`);
return; return;