Compare commits
4 Commits
main
...
core-loggi
| Author | SHA1 | Date |
|---|---|---|
|
|
6c5b20a89f | |
|
|
bd74802644 | |
|
|
dfc588096e | |
|
|
4379135168 |
|
|
@ -49,6 +49,22 @@ const testEnvVars = {
|
|||
const UUID = '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d'
|
||||
const DELIMITER = `ghadelimiter_${UUID}`
|
||||
|
||||
function extractErrorMetadata(error: Error): {
|
||||
file: string | undefined
|
||||
line: string | undefined
|
||||
column: string | undefined
|
||||
} {
|
||||
const stackLines = error.stack?.split(os.EOL) || []
|
||||
const firstTraceLine = stackLines[1]
|
||||
const match = firstTraceLine.match(/at (?:.*) \((.*):(\d+):(\d+)\)/) || []
|
||||
const [, file, line, column] = match
|
||||
return {
|
||||
file,
|
||||
line,
|
||||
column
|
||||
}
|
||||
}
|
||||
|
||||
describe('@actions/core', () => {
|
||||
beforeAll(() => {
|
||||
const filePath = path.join(__dirname, `test`)
|
||||
|
|
@ -379,9 +395,14 @@ describe('@actions/core', () => {
|
|||
|
||||
it('setFailed handles Error', () => {
|
||||
const message = 'this is my error message'
|
||||
core.setFailed(new Error(message))
|
||||
const error = new Error(message)
|
||||
|
||||
core.setFailed(error)
|
||||
expect(process.exitCode).toBe(core.ExitCode.Failure)
|
||||
assertWriteCalls([`::error::Error: ${message}${os.EOL}`])
|
||||
const {file, line, column} = extractErrorMetadata(error)
|
||||
assertWriteCalls([
|
||||
`::error title=Error,file=${file},line=${line},col=${column}::Error: ${message}${os.EOL}`
|
||||
])
|
||||
})
|
||||
|
||||
it('error sets the correct error message', () => {
|
||||
|
|
@ -396,11 +417,21 @@ describe('@actions/core', () => {
|
|||
|
||||
it('error handles an error object', () => {
|
||||
const message = 'this is my error message'
|
||||
core.error(new Error(message))
|
||||
const error = new Error(message)
|
||||
core.error(error)
|
||||
const {file, line, column} = extractErrorMetadata(error)
|
||||
assertWriteCalls([
|
||||
`::error title=Error,file=${file},line=${line},col=${column}::Error: ${message}${os.EOL}`
|
||||
])
|
||||
})
|
||||
|
||||
it('error handles an error object and an empty properties', () => {
|
||||
const message = 'this is my error message'
|
||||
core.error(new Error(message), {})
|
||||
assertWriteCalls([`::error::Error: ${message}${os.EOL}`])
|
||||
})
|
||||
|
||||
it('error handles parameters correctly', () => {
|
||||
it('error handles custom properties correctly', () => {
|
||||
const message = 'this is my error message'
|
||||
core.error(new Error(message), {
|
||||
title: 'A title',
|
||||
|
|
@ -427,11 +458,21 @@ describe('@actions/core', () => {
|
|||
|
||||
it('warning handles an error object', () => {
|
||||
const message = 'this is my error message'
|
||||
core.warning(new Error(message))
|
||||
const error = new Error(message)
|
||||
core.warning(error)
|
||||
const {file, line, column} = extractErrorMetadata(error)
|
||||
assertWriteCalls([
|
||||
`::warning title=Error,file=${file},line=${line},col=${column}::Error: ${message}${os.EOL}`
|
||||
])
|
||||
})
|
||||
|
||||
it('warning handles an error object and an empty properties', () => {
|
||||
const message = 'this is my error message'
|
||||
core.warning(new Error(message), {})
|
||||
assertWriteCalls([`::warning::Error: ${message}${os.EOL}`])
|
||||
})
|
||||
|
||||
it('warning handles parameters correctly', () => {
|
||||
it('warning handles custom properties correctly', () => {
|
||||
const message = 'this is my error message'
|
||||
core.warning(new Error(message), {
|
||||
title: 'A title',
|
||||
|
|
@ -458,11 +499,21 @@ describe('@actions/core', () => {
|
|||
|
||||
it('notice handles an error object', () => {
|
||||
const message = 'this is my error message'
|
||||
core.notice(new Error(message))
|
||||
const error = new Error(message)
|
||||
core.notice(error)
|
||||
const {file, line, column} = extractErrorMetadata(error)
|
||||
assertWriteCalls([
|
||||
`::notice title=Error,file=${file},line=${line},col=${column}::Error: ${message}${os.EOL}`
|
||||
])
|
||||
})
|
||||
|
||||
it('notice handles an error object and an empty properties', () => {
|
||||
const message = 'this is my error message'
|
||||
core.notice(new Error(message), {})
|
||||
assertWriteCalls([`::notice::Error: ${message}${os.EOL}`])
|
||||
})
|
||||
|
||||
it('notice handles parameters correctly', () => {
|
||||
it('notice handles custom properties correctly', () => {
|
||||
const message = 'this is my error message'
|
||||
core.notice(new Error(message), {
|
||||
title: 'A title',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
import {toAnnotationProperties} from '../src/utils'
|
||||
|
||||
describe('@actions/core/src/utils', () => {
|
||||
describe('.toAnnotationProperties', () => {
|
||||
it('extracts title only from Error instance without a parseable stack', () => {
|
||||
const error = new TypeError('Test error')
|
||||
error.stack = ''
|
||||
expect(toAnnotationProperties(error)).toEqual({
|
||||
title: 'TypeError',
|
||||
file: undefined,
|
||||
startLine: undefined,
|
||||
startColumn: undefined
|
||||
})
|
||||
})
|
||||
|
||||
it('extracts AnnotationProperties from Error instance', () => {
|
||||
const error = new ReferenceError('Test error')
|
||||
expect(toAnnotationProperties(error)).toEqual({
|
||||
title: 'ReferenceError',
|
||||
file: expect.stringMatching(/utils\.test\.ts$/),
|
||||
startLine: expect.any(Number),
|
||||
startColumn: expect.any(Number)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -11,6 +11,7 @@
|
|||
"dependencies": {
|
||||
"@actions/exec": "^1.1.1",
|
||||
"@actions/http-client": "^2.0.1",
|
||||
"error-stack-parser": "^2.1.4",
|
||||
"uuid": "^8.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
@ -51,6 +52,19 @@
|
|||
"integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==",
|
||||
"dev": true
|
||||
},
|
||||
"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/stackframe": {
|
||||
"version": "1.3.4",
|
||||
"resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz",
|
||||
"integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw=="
|
||||
},
|
||||
"node_modules/tunnel": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
|
||||
|
|
@ -102,6 +116,19 @@
|
|||
"integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==",
|
||||
"dev": true
|
||||
},
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"stackframe": {
|
||||
"version": "1.3.4",
|
||||
"resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz",
|
||||
"integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw=="
|
||||
},
|
||||
"tunnel": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
|
||||
|
|
|
|||
|
|
@ -38,10 +38,11 @@
|
|||
"dependencies": {
|
||||
"@actions/exec": "^1.1.1",
|
||||
"@actions/http-client": "^2.0.1",
|
||||
"error-stack-parser": "^2.1.4",
|
||||
"uuid": "^8.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^12.0.2",
|
||||
"@types/uuid": "^8.3.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
import {issue, issueCommand} from './command'
|
||||
import {issueFileCommand, prepareKeyValueMessage} from './file-command'
|
||||
import {toCommandProperties, toCommandValue} from './utils'
|
||||
|
||||
import {
|
||||
toAnnotationProperties,
|
||||
toCommandProperties,
|
||||
toCommandValue
|
||||
} from './utils'
|
||||
import * as os from 'os'
|
||||
import * as path from 'path'
|
||||
|
||||
|
|
@ -242,6 +245,21 @@ export function debug(message: string): void {
|
|||
issueCommand('debug', {}, message)
|
||||
}
|
||||
|
||||
function defaultAnnotationPropertes(
|
||||
message: string | Error,
|
||||
properties: AnnotationProperties | undefined = undefined
|
||||
): AnnotationProperties {
|
||||
// If no properties are provided, try to extract them from the Error instance
|
||||
if (properties === undefined) {
|
||||
if (message instanceof Error) {
|
||||
properties = toAnnotationProperties(message)
|
||||
} else {
|
||||
properties = {}
|
||||
}
|
||||
}
|
||||
return properties
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an error issue
|
||||
* @param message error issue message. Errors will be converted to string via toString()
|
||||
|
|
@ -249,8 +267,10 @@ export function debug(message: string): void {
|
|||
*/
|
||||
export function error(
|
||||
message: string | Error,
|
||||
properties: AnnotationProperties = {}
|
||||
properties: AnnotationProperties | undefined = undefined
|
||||
): void {
|
||||
properties = defaultAnnotationPropertes(message, properties)
|
||||
|
||||
issueCommand(
|
||||
'error',
|
||||
toCommandProperties(properties),
|
||||
|
|
@ -265,8 +285,10 @@ export function error(
|
|||
*/
|
||||
export function warning(
|
||||
message: string | Error,
|
||||
properties: AnnotationProperties = {}
|
||||
properties: AnnotationProperties | undefined = undefined
|
||||
): void {
|
||||
properties = defaultAnnotationPropertes(message, properties)
|
||||
|
||||
issueCommand(
|
||||
'warning',
|
||||
toCommandProperties(properties),
|
||||
|
|
@ -281,8 +303,10 @@ export function warning(
|
|||
*/
|
||||
export function notice(
|
||||
message: string | Error,
|
||||
properties: AnnotationProperties = {}
|
||||
properties: AnnotationProperties | undefined = undefined
|
||||
): void {
|
||||
properties = defaultAnnotationPropertes(message, properties)
|
||||
|
||||
issueCommand(
|
||||
'notice',
|
||||
toCommandProperties(properties),
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
import {AnnotationProperties} from './core'
|
||||
import {CommandProperties} from './command'
|
||||
import ErrorStackParser from 'error-stack-parser'
|
||||
|
||||
/**
|
||||
* Sanitizes an input into a string so it can be passed into issueCommand safely
|
||||
|
|
@ -39,3 +40,21 @@ export function toCommandProperties(
|
|||
endColumn: annotationProperties.endColumn
|
||||
}
|
||||
}
|
||||
|
||||
export function toAnnotationProperties(error: Error): AnnotationProperties {
|
||||
let firstFrame
|
||||
|
||||
try {
|
||||
const stack = ErrorStackParser.parse(error)
|
||||
firstFrame = stack?.[0]
|
||||
} catch (parseError) {
|
||||
// If we can't parse the stack, we'll just skip it
|
||||
}
|
||||
|
||||
return {
|
||||
title: error.name,
|
||||
file: firstFrame?.fileName,
|
||||
startLine: firstFrame?.lineNumber,
|
||||
startColumn: firstFrame?.columnNumber
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue