mirror of
https://github.com/actions/configure-pages.git
synced 2025-12-08 08:06:09 +00:00
Merge pull request #138 from actions/error-utils
Convert errors into Actions-compatible logging with annotations
This commit is contained in:
406
dist/index.js
vendored
406
dist/index.js
vendored
@@ -12749,6 +12749,213 @@ class Deprecation extends Error {
|
||||
exports.Deprecation = Deprecation;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 9176:
|
||||
/***/ (function(module, __unused_webpack_exports, __nccwpck_require__) {
|
||||
|
||||
(function(root, factory) {
|
||||
'use strict';
|
||||
// Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, Rhino, and browsers.
|
||||
|
||||
/* istanbul ignore next */
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
define('error-stack-parser', ['stackframe'], factory);
|
||||
} else if (true) {
|
||||
module.exports = factory(__nccwpck_require__(5046));
|
||||
} else {}
|
||||
}(this, function ErrorStackParser(StackFrame) {
|
||||
'use strict';
|
||||
|
||||
var FIREFOX_SAFARI_STACK_REGEXP = /(^|@)\S+:\d+/;
|
||||
var CHROME_IE_STACK_REGEXP = /^\s*at .*(\S+:\d+|\(native\))/m;
|
||||
var SAFARI_NATIVE_CODE_REGEXP = /^(eval@)?(\[native code])?$/;
|
||||
|
||||
return {
|
||||
/**
|
||||
* Given an Error object, extract the most information from it.
|
||||
*
|
||||
* @param {Error} error object
|
||||
* @return {Array} of StackFrames
|
||||
*/
|
||||
parse: function ErrorStackParser$$parse(error) {
|
||||
if (typeof error.stacktrace !== 'undefined' || typeof error['opera#sourceloc'] !== 'undefined') {
|
||||
return this.parseOpera(error);
|
||||
} else if (error.stack && error.stack.match(CHROME_IE_STACK_REGEXP)) {
|
||||
return this.parseV8OrIE(error);
|
||||
} else if (error.stack) {
|
||||
return this.parseFFOrSafari(error);
|
||||
} else {
|
||||
throw new Error('Cannot parse given Error object');
|
||||
}
|
||||
},
|
||||
|
||||
// Separate line and column numbers from a string of the form: (URI:Line:Column)
|
||||
extractLocation: function ErrorStackParser$$extractLocation(urlLike) {
|
||||
// Fail-fast but return locations like "(native)"
|
||||
if (urlLike.indexOf(':') === -1) {
|
||||
return [urlLike];
|
||||
}
|
||||
|
||||
var regExp = /(.+?)(?::(\d+))?(?::(\d+))?$/;
|
||||
var parts = regExp.exec(urlLike.replace(/[()]/g, ''));
|
||||
return [parts[1], parts[2] || undefined, parts[3] || undefined];
|
||||
},
|
||||
|
||||
parseV8OrIE: function ErrorStackParser$$parseV8OrIE(error) {
|
||||
var filtered = error.stack.split('\n').filter(function(line) {
|
||||
return !!line.match(CHROME_IE_STACK_REGEXP);
|
||||
}, this);
|
||||
|
||||
return filtered.map(function(line) {
|
||||
if (line.indexOf('(eval ') > -1) {
|
||||
// Throw away eval information until we implement stacktrace.js/stackframe#8
|
||||
line = line.replace(/eval code/g, 'eval').replace(/(\(eval at [^()]*)|(,.*$)/g, '');
|
||||
}
|
||||
var sanitizedLine = line.replace(/^\s+/, '').replace(/\(eval code/g, '(').replace(/^.*?\s+/, '');
|
||||
|
||||
// capture and preseve the parenthesized location "(/foo/my bar.js:12:87)" in
|
||||
// case it has spaces in it, as the string is split on \s+ later on
|
||||
var location = sanitizedLine.match(/ (\(.+\)$)/);
|
||||
|
||||
// remove the parenthesized location from the line, if it was matched
|
||||
sanitizedLine = location ? sanitizedLine.replace(location[0], '') : sanitizedLine;
|
||||
|
||||
// if a location was matched, pass it to extractLocation() otherwise pass all sanitizedLine
|
||||
// because this line doesn't have function name
|
||||
var locationParts = this.extractLocation(location ? location[1] : sanitizedLine);
|
||||
var functionName = location && sanitizedLine || undefined;
|
||||
var fileName = ['eval', '<anonymous>'].indexOf(locationParts[0]) > -1 ? undefined : locationParts[0];
|
||||
|
||||
return new StackFrame({
|
||||
functionName: functionName,
|
||||
fileName: fileName,
|
||||
lineNumber: locationParts[1],
|
||||
columnNumber: locationParts[2],
|
||||
source: line
|
||||
});
|
||||
}, this);
|
||||
},
|
||||
|
||||
parseFFOrSafari: function ErrorStackParser$$parseFFOrSafari(error) {
|
||||
var filtered = error.stack.split('\n').filter(function(line) {
|
||||
return !line.match(SAFARI_NATIVE_CODE_REGEXP);
|
||||
}, this);
|
||||
|
||||
return filtered.map(function(line) {
|
||||
// Throw away eval information until we implement stacktrace.js/stackframe#8
|
||||
if (line.indexOf(' > eval') > -1) {
|
||||
line = line.replace(/ line (\d+)(?: > eval line \d+)* > eval:\d+:\d+/g, ':$1');
|
||||
}
|
||||
|
||||
if (line.indexOf('@') === -1 && line.indexOf(':') === -1) {
|
||||
// Safari eval frames only have function names and nothing else
|
||||
return new StackFrame({
|
||||
functionName: line
|
||||
});
|
||||
} else {
|
||||
var functionNameRegex = /((.*".+"[^@]*)?[^@]*)(?:@)/;
|
||||
var matches = line.match(functionNameRegex);
|
||||
var functionName = matches && matches[1] ? matches[1] : undefined;
|
||||
var locationParts = this.extractLocation(line.replace(functionNameRegex, ''));
|
||||
|
||||
return new StackFrame({
|
||||
functionName: functionName,
|
||||
fileName: locationParts[0],
|
||||
lineNumber: locationParts[1],
|
||||
columnNumber: locationParts[2],
|
||||
source: line
|
||||
});
|
||||
}
|
||||
}, this);
|
||||
},
|
||||
|
||||
parseOpera: function ErrorStackParser$$parseOpera(e) {
|
||||
if (!e.stacktrace || (e.message.indexOf('\n') > -1 &&
|
||||
e.message.split('\n').length > e.stacktrace.split('\n').length)) {
|
||||
return this.parseOpera9(e);
|
||||
} else if (!e.stack) {
|
||||
return this.parseOpera10(e);
|
||||
} else {
|
||||
return this.parseOpera11(e);
|
||||
}
|
||||
},
|
||||
|
||||
parseOpera9: function ErrorStackParser$$parseOpera9(e) {
|
||||
var lineRE = /Line (\d+).*script (?:in )?(\S+)/i;
|
||||
var lines = e.message.split('\n');
|
||||
var result = [];
|
||||
|
||||
for (var i = 2, len = lines.length; i < len; i += 2) {
|
||||
var match = lineRE.exec(lines[i]);
|
||||
if (match) {
|
||||
result.push(new StackFrame({
|
||||
fileName: match[2],
|
||||
lineNumber: match[1],
|
||||
source: lines[i]
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
parseOpera10: function ErrorStackParser$$parseOpera10(e) {
|
||||
var lineRE = /Line (\d+).*script (?:in )?(\S+)(?:: In function (\S+))?$/i;
|
||||
var lines = e.stacktrace.split('\n');
|
||||
var result = [];
|
||||
|
||||
for (var i = 0, len = lines.length; i < len; i += 2) {
|
||||
var match = lineRE.exec(lines[i]);
|
||||
if (match) {
|
||||
result.push(
|
||||
new StackFrame({
|
||||
functionName: match[3] || undefined,
|
||||
fileName: match[2],
|
||||
lineNumber: match[1],
|
||||
source: lines[i]
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
// Opera 10.65+ Error.stack very similar to FF/Safari
|
||||
parseOpera11: function ErrorStackParser$$parseOpera11(error) {
|
||||
var filtered = error.stack.split('\n').filter(function(line) {
|
||||
return !!line.match(FIREFOX_SAFARI_STACK_REGEXP) && !line.match(/^Error created at/);
|
||||
}, this);
|
||||
|
||||
return filtered.map(function(line) {
|
||||
var tokens = line.split('@');
|
||||
var locationParts = this.extractLocation(tokens.pop());
|
||||
var functionCall = (tokens.shift() || '');
|
||||
var functionName = functionCall
|
||||
.replace(/<anonymous function(: (\w+))?>/, '$2')
|
||||
.replace(/\([^)]*\)/g, '') || undefined;
|
||||
var argsRaw;
|
||||
if (functionCall.match(/\(([^)]*)\)/)) {
|
||||
argsRaw = functionCall.replace(/^[^(]+\(([^)]*)\)$/, '$1');
|
||||
}
|
||||
var args = (argsRaw === undefined || argsRaw === '[arguments not available]') ?
|
||||
undefined : argsRaw.split(',');
|
||||
|
||||
return new StackFrame({
|
||||
functionName: functionName,
|
||||
args: args,
|
||||
fileName: locationParts[0],
|
||||
lineNumber: locationParts[1],
|
||||
columnNumber: locationParts[2],
|
||||
source: line
|
||||
});
|
||||
}, this);
|
||||
}
|
||||
};
|
||||
}));
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 1223:
|
||||
@@ -12798,6 +13005,154 @@ function onceStrict (fn) {
|
||||
}
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 5046:
|
||||
/***/ (function(module) {
|
||||
|
||||
(function(root, factory) {
|
||||
'use strict';
|
||||
// Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, Rhino, and browsers.
|
||||
|
||||
/* istanbul ignore next */
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
define('stackframe', [], factory);
|
||||
} else if (true) {
|
||||
module.exports = factory();
|
||||
} else {}
|
||||
}(this, function() {
|
||||
'use strict';
|
||||
function _isNumber(n) {
|
||||
return !isNaN(parseFloat(n)) && isFinite(n);
|
||||
}
|
||||
|
||||
function _capitalize(str) {
|
||||
return str.charAt(0).toUpperCase() + str.substring(1);
|
||||
}
|
||||
|
||||
function _getter(p) {
|
||||
return function() {
|
||||
return this[p];
|
||||
};
|
||||
}
|
||||
|
||||
var booleanProps = ['isConstructor', 'isEval', 'isNative', 'isToplevel'];
|
||||
var numericProps = ['columnNumber', 'lineNumber'];
|
||||
var stringProps = ['fileName', 'functionName', 'source'];
|
||||
var arrayProps = ['args'];
|
||||
var objectProps = ['evalOrigin'];
|
||||
|
||||
var props = booleanProps.concat(numericProps, stringProps, arrayProps, objectProps);
|
||||
|
||||
function StackFrame(obj) {
|
||||
if (!obj) return;
|
||||
for (var i = 0; i < props.length; i++) {
|
||||
if (obj[props[i]] !== undefined) {
|
||||
this['set' + _capitalize(props[i])](obj[props[i]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StackFrame.prototype = {
|
||||
getArgs: function() {
|
||||
return this.args;
|
||||
},
|
||||
setArgs: function(v) {
|
||||
if (Object.prototype.toString.call(v) !== '[object Array]') {
|
||||
throw new TypeError('Args must be an Array');
|
||||
}
|
||||
this.args = v;
|
||||
},
|
||||
|
||||
getEvalOrigin: function() {
|
||||
return this.evalOrigin;
|
||||
},
|
||||
setEvalOrigin: function(v) {
|
||||
if (v instanceof StackFrame) {
|
||||
this.evalOrigin = v;
|
||||
} else if (v instanceof Object) {
|
||||
this.evalOrigin = new StackFrame(v);
|
||||
} else {
|
||||
throw new TypeError('Eval Origin must be an Object or StackFrame');
|
||||
}
|
||||
},
|
||||
|
||||
toString: function() {
|
||||
var fileName = this.getFileName() || '';
|
||||
var lineNumber = this.getLineNumber() || '';
|
||||
var columnNumber = this.getColumnNumber() || '';
|
||||
var functionName = this.getFunctionName() || '';
|
||||
if (this.getIsEval()) {
|
||||
if (fileName) {
|
||||
return '[eval] (' + fileName + ':' + lineNumber + ':' + columnNumber + ')';
|
||||
}
|
||||
return '[eval]:' + lineNumber + ':' + columnNumber;
|
||||
}
|
||||
if (functionName) {
|
||||
return functionName + ' (' + fileName + ':' + lineNumber + ':' + columnNumber + ')';
|
||||
}
|
||||
return fileName + ':' + lineNumber + ':' + columnNumber;
|
||||
}
|
||||
};
|
||||
|
||||
StackFrame.fromString = function StackFrame$$fromString(str) {
|
||||
var argsStartIndex = str.indexOf('(');
|
||||
var argsEndIndex = str.lastIndexOf(')');
|
||||
|
||||
var functionName = str.substring(0, argsStartIndex);
|
||||
var args = str.substring(argsStartIndex + 1, argsEndIndex).split(',');
|
||||
var locationString = str.substring(argsEndIndex + 1);
|
||||
|
||||
if (locationString.indexOf('@') === 0) {
|
||||
var parts = /@(.+?)(?::(\d+))?(?::(\d+))?$/.exec(locationString, '');
|
||||
var fileName = parts[1];
|
||||
var lineNumber = parts[2];
|
||||
var columnNumber = parts[3];
|
||||
}
|
||||
|
||||
return new StackFrame({
|
||||
functionName: functionName,
|
||||
args: args || undefined,
|
||||
fileName: fileName,
|
||||
lineNumber: lineNumber || undefined,
|
||||
columnNumber: columnNumber || undefined
|
||||
});
|
||||
};
|
||||
|
||||
for (var i = 0; i < booleanProps.length; i++) {
|
||||
StackFrame.prototype['get' + _capitalize(booleanProps[i])] = _getter(booleanProps[i]);
|
||||
StackFrame.prototype['set' + _capitalize(booleanProps[i])] = (function(p) {
|
||||
return function(v) {
|
||||
this[p] = Boolean(v);
|
||||
};
|
||||
})(booleanProps[i]);
|
||||
}
|
||||
|
||||
for (var j = 0; j < numericProps.length; j++) {
|
||||
StackFrame.prototype['get' + _capitalize(numericProps[j])] = _getter(numericProps[j]);
|
||||
StackFrame.prototype['set' + _capitalize(numericProps[j])] = (function(p) {
|
||||
return function(v) {
|
||||
if (!_isNumber(v)) {
|
||||
throw new TypeError(p + ' must be a Number');
|
||||
}
|
||||
this[p] = Number(v);
|
||||
};
|
||||
})(numericProps[j]);
|
||||
}
|
||||
|
||||
for (var k = 0; k < stringProps.length; k++) {
|
||||
StackFrame.prototype['get' + _capitalize(stringProps[k])] = _getter(stringProps[k]);
|
||||
StackFrame.prototype['set' + _capitalize(stringProps[k])] = (function(p) {
|
||||
return function(v) {
|
||||
this[p] = String(v);
|
||||
};
|
||||
})(stringProps[k]);
|
||||
}
|
||||
|
||||
return StackFrame;
|
||||
}));
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 4294:
|
||||
@@ -35742,6 +36097,7 @@ function wrappy (fn, cb) {
|
||||
|
||||
const core = __nccwpck_require__(2186)
|
||||
const github = __nccwpck_require__(5438)
|
||||
const { convertErrorToAnnotationProperties } = __nccwpck_require__(1507)
|
||||
|
||||
async function enablePagesSite({ githubToken }) {
|
||||
const octokit = github.getOctokit(githubToken)
|
||||
@@ -35785,12 +36141,12 @@ async function findOrCreatePagesSite({ githubToken, enablement = true }) {
|
||||
} catch (error) {
|
||||
if (!enablement) {
|
||||
core.error(
|
||||
'Get Pages site failed. Please verify that the repository has Pages enabled and configured to build using GitHub Actions, or consider exploring the `enablement` parameter for this action.',
|
||||
error
|
||||
`Get Pages site failed. Please verify that the repository has Pages enabled and configured to build using GitHub Actions, or consider exploring the \`enablement\` parameter for this action. Error: ${error.message}`,
|
||||
convertErrorToAnnotationProperties(error)
|
||||
)
|
||||
throw error
|
||||
}
|
||||
core.warning('Get Pages site failed', error)
|
||||
core.warning(`Get Pages site failed. Error: ${error.message}`, convertErrorToAnnotationProperties(error))
|
||||
}
|
||||
|
||||
if (!pageObject && enablement) {
|
||||
@@ -35798,7 +36154,7 @@ async function findOrCreatePagesSite({ githubToken, enablement = true }) {
|
||||
try {
|
||||
pageObject = await enablePagesSite({ githubToken })
|
||||
} catch (error) {
|
||||
core.error('Create Pages site failed', error)
|
||||
core.error(`Create Pages site failed. Error: ${error.message}`, convertErrorToAnnotationProperties(error))
|
||||
throw error
|
||||
}
|
||||
|
||||
@@ -35808,7 +36164,7 @@ async function findOrCreatePagesSite({ githubToken, enablement = true }) {
|
||||
try {
|
||||
pageObject = await getPagesSite({ githubToken })
|
||||
} catch (error) {
|
||||
core.error('Get Pages site still failed', error)
|
||||
core.error(`Get Pages site still failed. Error: ${error.message}`, convertErrorToAnnotationProperties(error))
|
||||
throw error
|
||||
}
|
||||
}
|
||||
@@ -36295,6 +36651,37 @@ function getContext() {
|
||||
module.exports = { getContext }
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 1507:
|
||||
/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
|
||||
|
||||
const ErrorStackParser = __nccwpck_require__(9176)
|
||||
|
||||
// Convert an Error's stack into `@actions/core` toolkit AnnotationProperties:
|
||||
// https://github.com/actions/toolkit/blob/ef77c9d60bdb03700d7758b0d04b88446e72a896/packages/core/src/core.ts#L36-L71
|
||||
function convertErrorToAnnotationProperties(error, title = error.name) {
|
||||
if (!(error instanceof Error)) {
|
||||
throw new TypeError('error must be an instance of Error')
|
||||
}
|
||||
|
||||
const stack = ErrorStackParser.parse(error)
|
||||
const firstFrame = stack && stack.length > 0 ? stack[0] : null
|
||||
if (!firstFrame) {
|
||||
throw new Error('Error stack is empty or unparseable')
|
||||
}
|
||||
|
||||
return {
|
||||
title,
|
||||
file: firstFrame.fileName,
|
||||
startLine: firstFrame.lineNumber,
|
||||
startColumn: firstFrame.columnNumber
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { convertErrorToAnnotationProperties }
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 7527:
|
||||
@@ -36335,6 +36722,7 @@ module.exports = function removeTrailingSlash(str) {
|
||||
const core = __nccwpck_require__(2186)
|
||||
const { ConfigParser } = __nccwpck_require__(8395)
|
||||
const removeTrailingSlash = __nccwpck_require__(9255)
|
||||
const { convertErrorToAnnotationProperties } = __nccwpck_require__(1507)
|
||||
|
||||
const SUPPORTED_FILE_EXTENSIONS = ['.js', '.cjs', '.mjs']
|
||||
|
||||
@@ -36422,13 +36810,13 @@ function setPagesConfig({ staticSiteGenerator, generatorConfigFile, siteUrl }) {
|
||||
core.warning(
|
||||
`Unsupported configuration file extension. Currently supported extensions: ${SUPPORTED_FILE_EXTENSIONS.map(
|
||||
ext => JSON.stringify(ext)
|
||||
).join(', ')}`,
|
||||
error
|
||||
).join(', ')}. Error: ${error.message}`,
|
||||
convertErrorToAnnotationProperties(error)
|
||||
)
|
||||
} else {
|
||||
core.warning(
|
||||
`We were unable to determine how to inject the site metadata into your config. Generated URLs may be incorrect. The base URL for this site should be ${siteUrl}. Please ensure your framework is configured to generate relative links appropriately.`,
|
||||
error
|
||||
`We were unable to determine how to inject the site metadata into your config. Generated URLs may be incorrect. The base URL for this site should be ${siteUrl}. Please ensure your framework is configured to generate relative links appropriately. Error: ${error.message}`,
|
||||
convertErrorToAnnotationProperties(error)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
2
dist/index.js.map
vendored
2
dist/index.js.map
vendored
File diff suppressed because one or more lines are too long
46
dist/licenses.txt
vendored
46
dist/licenses.txt
vendored
@@ -513,6 +513,29 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
|
||||
error-stack-parser
|
||||
MIT
|
||||
Copyright (c) 2017 Eric Wendelin and other contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
eslint-visitor-keys
|
||||
Apache-2.0
|
||||
Apache License
|
||||
@@ -766,6 +789,29 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
|
||||
stackframe
|
||||
MIT
|
||||
Copyright (c) 2017 Eric Wendelin and other contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
tunnel
|
||||
MIT
|
||||
The MIT License (MIT)
|
||||
|
||||
28
package-lock.json
generated
28
package-lock.json
generated
@@ -11,9 +11,11 @@
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.10.1",
|
||||
"@actions/github": "^6.0.0",
|
||||
"error-stack-parser": "^2.1.4",
|
||||
"espree": "^9.6.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@octokit/request-error": "^5.0.1",
|
||||
"@vercel/ncc": "^0.38.1",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
@@ -2793,6 +2795,14 @@
|
||||
"is-arrayish": "^0.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/error-stack-parser": {
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz",
|
||||
"integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==",
|
||||
"dependencies": {
|
||||
"stackframe": "^1.3.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-abstract": {
|
||||
"version": "1.21.1",
|
||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.1.tgz",
|
||||
@@ -6145,6 +6155,11 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/stackframe": {
|
||||
"version": "1.3.4",
|
||||
"resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz",
|
||||
"integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw=="
|
||||
},
|
||||
"node_modules/stop-iteration-iterator": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz",
|
||||
@@ -8805,6 +8820,14 @@
|
||||
"is-arrayish": "^0.2.1"
|
||||
}
|
||||
},
|
||||
"error-stack-parser": {
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz",
|
||||
"integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==",
|
||||
"requires": {
|
||||
"stackframe": "^1.3.4"
|
||||
}
|
||||
},
|
||||
"es-abstract": {
|
||||
"version": "1.21.1",
|
||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.1.tgz",
|
||||
@@ -11242,6 +11265,11 @@
|
||||
"escape-string-regexp": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"stackframe": {
|
||||
"version": "1.3.4",
|
||||
"resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz",
|
||||
"integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw=="
|
||||
},
|
||||
"stop-iteration-iterator": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz",
|
||||
|
||||
@@ -26,9 +26,11 @@
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.10.1",
|
||||
"@actions/github": "^6.0.0",
|
||||
"error-stack-parser": "^2.1.4",
|
||||
"espree": "^9.6.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@octokit/request-error": "^5.0.1",
|
||||
"@vercel/ncc": "^0.38.1",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
const core = require('@actions/core')
|
||||
const github = require('@actions/github')
|
||||
const { convertErrorToAnnotationProperties } = require('./error-utils')
|
||||
|
||||
async function enablePagesSite({ githubToken }) {
|
||||
const octokit = github.getOctokit(githubToken)
|
||||
@@ -43,12 +44,12 @@ async function findOrCreatePagesSite({ githubToken, enablement = true }) {
|
||||
} catch (error) {
|
||||
if (!enablement) {
|
||||
core.error(
|
||||
'Get Pages site failed. Please verify that the repository has Pages enabled and configured to build using GitHub Actions, or consider exploring the `enablement` parameter for this action.',
|
||||
error
|
||||
`Get Pages site failed. Please verify that the repository has Pages enabled and configured to build using GitHub Actions, or consider exploring the \`enablement\` parameter for this action. Error: ${error.message}`,
|
||||
convertErrorToAnnotationProperties(error)
|
||||
)
|
||||
throw error
|
||||
}
|
||||
core.warning('Get Pages site failed', error)
|
||||
core.warning(`Get Pages site failed. Error: ${error.message}`, convertErrorToAnnotationProperties(error))
|
||||
}
|
||||
|
||||
if (!pageObject && enablement) {
|
||||
@@ -56,7 +57,7 @@ async function findOrCreatePagesSite({ githubToken, enablement = true }) {
|
||||
try {
|
||||
pageObject = await enablePagesSite({ githubToken })
|
||||
} catch (error) {
|
||||
core.error('Create Pages site failed', error)
|
||||
core.error(`Create Pages site failed. Error: ${error.message}`, convertErrorToAnnotationProperties(error))
|
||||
throw error
|
||||
}
|
||||
|
||||
@@ -66,7 +67,7 @@ async function findOrCreatePagesSite({ githubToken, enablement = true }) {
|
||||
try {
|
||||
pageObject = await getPagesSite({ githubToken })
|
||||
} catch (error) {
|
||||
core.error('Get Pages site still failed', error)
|
||||
core.error(`Get Pages site still failed. Error: ${error.message}`, convertErrorToAnnotationProperties(error))
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,24 @@
|
||||
const core = require('@actions/core')
|
||||
const apiClient = require('./api-client')
|
||||
const { RequestError } = require('@octokit/request-error')
|
||||
|
||||
const mockGetPages = jest.fn()
|
||||
const mockCreatePagesSite = jest.fn()
|
||||
|
||||
const generateRequestError = statusCode => {
|
||||
const fakeRequest = { headers: {}, url: '/' }
|
||||
const fakeResponse = { status: statusCode }
|
||||
let message = 'Oops'
|
||||
if (statusCode === 404) {
|
||||
message = 'Not Found'
|
||||
}
|
||||
if (statusCode === 409) {
|
||||
message = 'Too Busy'
|
||||
}
|
||||
const error = new RequestError(message, statusCode, { request: fakeRequest, response: fakeResponse })
|
||||
return error
|
||||
}
|
||||
|
||||
jest.mock('@actions/github', () => ({
|
||||
context: {
|
||||
repo: {
|
||||
@@ -48,7 +63,7 @@ describe('apiClient', () => {
|
||||
})
|
||||
|
||||
it('handles a 409 response when the page already exists', async () => {
|
||||
mockCreatePagesSite.mockImplementationOnce(() => Promise.reject({ response: { status: 409 } }))
|
||||
mockCreatePagesSite.mockImplementationOnce(() => Promise.reject(generateRequestError(409)))
|
||||
|
||||
// Simply assert that no error is raised
|
||||
const result = await apiClient.enablePagesSite({
|
||||
@@ -59,7 +74,7 @@ describe('apiClient', () => {
|
||||
})
|
||||
|
||||
it('re-raises errors on failure status codes', async () => {
|
||||
mockCreatePagesSite.mockImplementationOnce(() => Promise.reject({ response: { status: 404 } }))
|
||||
mockCreatePagesSite.mockImplementationOnce(() => Promise.reject(generateRequestError(404)))
|
||||
|
||||
let erred = false
|
||||
try {
|
||||
@@ -86,7 +101,7 @@ describe('apiClient', () => {
|
||||
})
|
||||
|
||||
it('re-raises errors on failure status codes', async () => {
|
||||
mockGetPages.mockImplementationOnce(() => Promise.reject({ response: { status: 404 } }))
|
||||
mockGetPages.mockImplementationOnce(() => Promise.reject(generateRequestError(404)))
|
||||
|
||||
let erred = false
|
||||
try {
|
||||
@@ -105,7 +120,7 @@ describe('apiClient', () => {
|
||||
it('does not make a request to create a page if it already exists', async () => {
|
||||
const PAGE_OBJECT = { html_url: 'https://actions.github.io/is-awesome/' }
|
||||
mockGetPages.mockImplementationOnce(() => Promise.resolve({ status: 200, data: PAGE_OBJECT }))
|
||||
mockCreatePagesSite.mockImplementationOnce(() => Promise.reject({ response: { status: 404 } }))
|
||||
mockCreatePagesSite.mockImplementationOnce(() => Promise.reject(generateRequestError(404)))
|
||||
|
||||
const result = await apiClient.findOrCreatePagesSite({
|
||||
githubToken: GITHUB_TOKEN
|
||||
@@ -117,7 +132,7 @@ describe('apiClient', () => {
|
||||
|
||||
it('makes request to create a page by default if it does not exist', async () => {
|
||||
const PAGE_OBJECT = { html_url: 'https://actions.github.io/is-awesome/' }
|
||||
mockGetPages.mockImplementationOnce(() => Promise.reject({ response: { status: 404 } }))
|
||||
mockGetPages.mockImplementationOnce(() => Promise.reject(generateRequestError(404)))
|
||||
mockCreatePagesSite.mockImplementationOnce(() => Promise.resolve({ status: 201, data: PAGE_OBJECT }))
|
||||
|
||||
const result = await apiClient.findOrCreatePagesSite({
|
||||
@@ -130,7 +145,7 @@ describe('apiClient', () => {
|
||||
|
||||
it('makes a request to create a page when explicitly enabled if it does not exist', async () => {
|
||||
const PAGE_OBJECT = { html_url: 'https://actions.github.io/is-awesome/' }
|
||||
mockGetPages.mockImplementationOnce(() => Promise.reject({ response: { status: 404 } }))
|
||||
mockGetPages.mockImplementationOnce(() => Promise.reject(generateRequestError(404)))
|
||||
mockCreatePagesSite.mockImplementationOnce(() => Promise.resolve({ status: 201, data: PAGE_OBJECT }))
|
||||
|
||||
const result = await apiClient.findOrCreatePagesSite({
|
||||
@@ -143,8 +158,8 @@ describe('apiClient', () => {
|
||||
})
|
||||
|
||||
it('does not make a request to create a page when explicitly disabled even if it does not exist', async () => {
|
||||
mockGetPages.mockImplementationOnce(() => Promise.reject({ response: { status: 404 } }))
|
||||
mockCreatePagesSite.mockImplementationOnce(() => Promise.reject({ response: { status: 500 } })) // just so they both aren't 404
|
||||
mockGetPages.mockImplementationOnce(() => Promise.reject(generateRequestError(404)))
|
||||
mockCreatePagesSite.mockImplementationOnce(() => Promise.reject(generateRequestError(500))) // just so they both aren't 404
|
||||
|
||||
let erred = false
|
||||
try {
|
||||
@@ -163,8 +178,8 @@ describe('apiClient', () => {
|
||||
})
|
||||
|
||||
it('does not make a second request to get page if create fails for reason other than existence', async () => {
|
||||
mockGetPages.mockImplementationOnce(() => Promise.reject({ response: { status: 404 } }))
|
||||
mockCreatePagesSite.mockImplementationOnce(() => Promise.reject({ response: { status: 500 } })) // just so they both aren't 404
|
||||
mockGetPages.mockImplementationOnce(() => Promise.reject(generateRequestError(404)))
|
||||
mockCreatePagesSite.mockImplementationOnce(() => Promise.reject(generateRequestError(500))) // just so they both aren't 404
|
||||
|
||||
let erred = false
|
||||
try {
|
||||
@@ -184,9 +199,9 @@ describe('apiClient', () => {
|
||||
it('makes second request to get page if create fails because of existence', async () => {
|
||||
const PAGE_OBJECT = { html_url: 'https://actions.github.io/is-awesome/' }
|
||||
mockGetPages
|
||||
.mockImplementationOnce(() => Promise.reject({ response: { status: 404 } }))
|
||||
.mockImplementationOnce(() => Promise.reject(generateRequestError(404)))
|
||||
.mockImplementationOnce(() => Promise.resolve({ status: 200, data: PAGE_OBJECT }))
|
||||
mockCreatePagesSite.mockImplementationOnce(() => Promise.reject({ response: { status: 409 } }))
|
||||
mockCreatePagesSite.mockImplementationOnce(() => Promise.reject(generateRequestError(409)))
|
||||
|
||||
const result = await apiClient.findOrCreatePagesSite({
|
||||
githubToken: GITHUB_TOKEN
|
||||
|
||||
24
src/error-utils.js
Normal file
24
src/error-utils.js
Normal file
@@ -0,0 +1,24 @@
|
||||
const ErrorStackParser = require('error-stack-parser')
|
||||
|
||||
// Convert an Error's stack into `@actions/core` toolkit AnnotationProperties:
|
||||
// https://github.com/actions/toolkit/blob/ef77c9d60bdb03700d7758b0d04b88446e72a896/packages/core/src/core.ts#L36-L71
|
||||
function convertErrorToAnnotationProperties(error, title = error.name) {
|
||||
if (!(error instanceof Error)) {
|
||||
throw new TypeError('error must be an instance of Error')
|
||||
}
|
||||
|
||||
const stack = ErrorStackParser.parse(error)
|
||||
const firstFrame = stack && stack.length > 0 ? stack[0] : null
|
||||
if (!firstFrame) {
|
||||
throw new Error('Error stack is empty or unparseable')
|
||||
}
|
||||
|
||||
return {
|
||||
title,
|
||||
file: firstFrame.fileName,
|
||||
startLine: firstFrame.lineNumber,
|
||||
startColumn: firstFrame.columnNumber
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { convertErrorToAnnotationProperties }
|
||||
38
src/error-utils.test.js
Normal file
38
src/error-utils.test.js
Normal file
@@ -0,0 +1,38 @@
|
||||
const { convertErrorToAnnotationProperties } = require('./error-utils')
|
||||
|
||||
describe('error-utils', () => {
|
||||
describe('convertErrorToAnnotationProperties', () => {
|
||||
it('throws a TypeError if the first argument is not an Error instance', () => {
|
||||
expect(() => convertErrorToAnnotationProperties('not an Error')).toThrow(
|
||||
TypeError,
|
||||
'error must be an instance of Error'
|
||||
)
|
||||
})
|
||||
|
||||
it('throws an Error if the first argument is an Error instance without a parseable stack', () => {
|
||||
const error = new Error('Test error')
|
||||
error.stack = ''
|
||||
expect(() => convertErrorToAnnotationProperties(error)).toThrow(Error, 'Error stack is empty or unparseable')
|
||||
})
|
||||
|
||||
it('returns an AnnotationProperties-compatible object', () => {
|
||||
const result = convertErrorToAnnotationProperties(new TypeError('Test error'))
|
||||
expect(result).toEqual({
|
||||
title: 'TypeError',
|
||||
file: __filename,
|
||||
startLine: expect.any(Number),
|
||||
startColumn: expect.any(Number)
|
||||
})
|
||||
})
|
||||
|
||||
it('returns an AnnotationProperties-compatible object with a custom title', () => {
|
||||
const result = convertErrorToAnnotationProperties(new TypeError('Test error'), 'custom title')
|
||||
expect(result).toEqual({
|
||||
title: 'custom title',
|
||||
file: __filename,
|
||||
startLine: expect.any(Number),
|
||||
startColumn: expect.any(Number)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,6 +1,7 @@
|
||||
const core = require('@actions/core')
|
||||
const { ConfigParser } = require('./config-parser')
|
||||
const removeTrailingSlash = require('./remove-trailing-slash')
|
||||
const { convertErrorToAnnotationProperties } = require('./error-utils')
|
||||
|
||||
const SUPPORTED_FILE_EXTENSIONS = ['.js', '.cjs', '.mjs']
|
||||
|
||||
@@ -88,13 +89,13 @@ function setPagesConfig({ staticSiteGenerator, generatorConfigFile, siteUrl }) {
|
||||
core.warning(
|
||||
`Unsupported configuration file extension. Currently supported extensions: ${SUPPORTED_FILE_EXTENSIONS.map(
|
||||
ext => JSON.stringify(ext)
|
||||
).join(', ')}`,
|
||||
error
|
||||
).join(', ')}. Error: ${error.message}`,
|
||||
convertErrorToAnnotationProperties(error)
|
||||
)
|
||||
} else {
|
||||
core.warning(
|
||||
`We were unable to determine how to inject the site metadata into your config. Generated URLs may be incorrect. The base URL for this site should be ${siteUrl}. Please ensure your framework is configured to generate relative links appropriately.`,
|
||||
error
|
||||
`We were unable to determine how to inject the site metadata into your config. Generated URLs may be incorrect. The base URL for this site should be ${siteUrl}. Please ensure your framework is configured to generate relative links appropriately. Error: ${error.message}`,
|
||||
convertErrorToAnnotationProperties(error)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user