Skip to content

Commit db4c1d0

Browse files
feat(sam): filter known sam cli errors
The sam cli may fail when executing operations internally. An example is trying to debug a lambda using python, but a specific python version does not exist. This commit now has the sam cli invoker collect accepted errors (based off certain prefixes) and throws them instead of indicating 'no message available' You can test this by: - Running the 'Extenstion' debugger - Creating a python3.7 SAM lambda application - Run and debug the lambda function - An error message window will appear telling you it could not find the python3.7 runtime (assuming you don't have it locally) Signed-off-by: Nikolas Komonen <[email protected]>
1 parent 7c57128 commit db4c1d0

File tree

2 files changed

+76
-1
lines changed

2 files changed

+76
-1
lines changed

src/shared/sam/cli/samCliInvokerUtils.ts

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,42 @@ export function logAndThrowIfUnexpectedExitCode(processResult: ChildProcessResul
5555
message = processResult.error.message
5656
}
5757
}
58+
const usefulErrors = collectAcceptedErrorMessages(processResult.stderr).join('\n')
59+
throw makeUnexpectedExitCodeError(message ?? usefulErrors)
60+
}
61+
62+
/**
63+
* Collect known errors messages from a sam error message
64+
* that may have multiple errors in one message.
65+
* @param errors A string that can have multiple error messages
66+
*/
67+
export function collectAcceptedErrorMessages(errorMessage: string): string[] {
68+
const errors = errorMessage.split('\n')
69+
const shouldCollectFuncs = [_startsWithEscapeSequence, _startsWithError]
70+
return errors.filter(error => {
71+
return shouldCollectFuncs.some(shouldCollect => {
72+
return shouldCollect(error)
73+
})
74+
})
75+
}
76+
77+
/**
78+
* Returns true if text starts with an escape
79+
* sequence with one of the accepted sequences.
80+
*/
81+
function _startsWithEscapeSequence(text: string): boolean {
82+
const escapeInDecimal = 27
83+
if (text.charCodeAt(0) !== escapeInDecimal) {
84+
return false
85+
}
86+
87+
const remainingText = text.substring(1)
88+
const acceptedSequences = ['[33m']
89+
return acceptedSequences.some(code => {
90+
return remainingText.startsWith(code)
91+
})
92+
}
5893

59-
throw makeUnexpectedExitCodeError(message ?? 'no message available')
94+
function _startsWithError(text: string): boolean {
95+
return text.startsWith('Error:')
6096
}

src/test/shared/sam/cli/samCliInvokerUtils.test.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import * as assert from 'assert'
77
import {
8+
collectAcceptedErrorMessages,
89
logAndThrowIfUnexpectedExitCode,
910
makeUnexpectedExitCodeError,
1011
} from '../../../../shared/sam/cli/samCliInvokerUtils'
@@ -42,3 +43,41 @@ describe('logAndThrowIfUnexpectedExitCode', async function () {
4243
await assertLogContainsBadExitInformation(getTestLogger(), childProcessResult, 456)
4344
})
4445
})
46+
47+
/**
48+
* Returns a string with the 'Escape' character
49+
* prepended to the given text.
50+
*
51+
* This exists because using '\e' does not
52+
* work.
53+
*/
54+
function prependEscapeCode(text: string): string {
55+
return String.fromCharCode(27) + text
56+
}
57+
58+
describe('collectAcceptedErrorMessages()', async () => {
59+
let result: string[]
60+
61+
before(async () => {
62+
const input = [
63+
prependEscapeCode('[33m This is an accepted escape sequence'),
64+
prependEscapeCode('[100m This is not an accepted escape sequence'),
65+
'This will be ignored',
66+
'Error: This is accepted due to the prefix',
67+
].join('\n')
68+
result = collectAcceptedErrorMessages(input)
69+
})
70+
71+
it('has the expected amount of messages', async () => {
72+
assert.strictEqual(result.length, 2)
73+
})
74+
it('collects the "Error:" prefix', async () => {
75+
assert(result.includes('Error: This is accepted due to the prefix'))
76+
})
77+
it('collects accepted escape sequence prefixes', async () => {
78+
assert(result.includes(prependEscapeCode('[33m This is an accepted escape sequence')))
79+
})
80+
it('ignores non-accepted escape sequence prefixes', async () => {
81+
assert(!result.includes(prependEscapeCode('[100m This is not an accepted escape sequence')))
82+
})
83+
})

0 commit comments

Comments
 (0)