Skip to content

Commit 3cf0738

Browse files
authored
do not stream function logs if stack does not exist (#2315)
* start streaming function logs if deployment successful * update detection of BackendOutputClientErrors * change to not stream only if stack does not exist * update changeset * remove eslint package from changeset
1 parent a713a02 commit 3cf0738

File tree

12 files changed

+173
-17
lines changed

12 files changed

+173
-17
lines changed

.changeset/few-candles-wink.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
'@aws-amplify/deployed-backend-client': minor
3+
'@aws-amplify/model-generator': patch
4+
'@aws-amplify/client-config': patch
5+
'@aws-amplify/backend-cli': patch
6+
---
7+
8+
update detection of BackendOutputClientErrors

.changeset/great-mugs-warn.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@aws-amplify/sandbox': patch
3+
---
4+
5+
do not stream function logs if stack does not exist

packages/cli/src/commands/generate/forms/generate_forms_command.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ export class GenerateFormsCommand
8383
output = await backendOutputClient.getOutput(backendIdentifier);
8484
} catch (error) {
8585
if (
86-
error instanceof BackendOutputClientError &&
86+
BackendOutputClientError.isBackendOutputClientError(error) &&
8787
error.code === BackendOutputClientErrorType.DEPLOYMENT_IN_PROGRESS
8888
) {
8989
throw new AmplifyUserError(
@@ -96,7 +96,7 @@ export class GenerateFormsCommand
9696
);
9797
}
9898
if (
99-
error instanceof BackendOutputClientError &&
99+
BackendOutputClientError.isBackendOutputClientError(error) &&
100100
error.code === BackendOutputClientErrorType.NO_STACK_FOUND
101101
) {
102102
throw new AmplifyUserError(
@@ -110,7 +110,7 @@ export class GenerateFormsCommand
110110
);
111111
}
112112
if (
113-
error instanceof BackendOutputClientError &&
113+
BackendOutputClientError.isBackendOutputClientError(error) &&
114114
error.code === BackendOutputClientErrorType.CREDENTIALS_ERROR
115115
) {
116116
throw new AmplifyUserError(
@@ -125,7 +125,7 @@ export class GenerateFormsCommand
125125
);
126126
}
127127
if (
128-
error instanceof BackendOutputClientError &&
128+
BackendOutputClientError.isBackendOutputClientError(error) &&
129129
error.code === BackendOutputClientErrorType.ACCESS_DENIED
130130
) {
131131
throw new AmplifyUserError(

packages/client-config/src/unified_client_config_generator.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export class UnifiedClientConfigGenerator implements ClientConfigGenerator {
4040
output = await this.fetchOutput();
4141
} catch (error) {
4242
if (
43-
error instanceof BackendOutputClientError &&
43+
BackendOutputClientError.isBackendOutputClientError(error) &&
4444
error.code === BackendOutputClientErrorType.DEPLOYMENT_IN_PROGRESS
4545
) {
4646
throw new AmplifyUserError(
@@ -53,7 +53,7 @@ export class UnifiedClientConfigGenerator implements ClientConfigGenerator {
5353
);
5454
}
5555
if (
56-
error instanceof BackendOutputClientError &&
56+
BackendOutputClientError.isBackendOutputClientError(error) &&
5757
error.code === BackendOutputClientErrorType.NO_STACK_FOUND
5858
) {
5959
throw new AmplifyUserError(
@@ -67,7 +67,7 @@ export class UnifiedClientConfigGenerator implements ClientConfigGenerator {
6767
);
6868
}
6969
if (
70-
error instanceof BackendOutputClientError &&
70+
BackendOutputClientError.isBackendOutputClientError(error) &&
7171
error.code === BackendOutputClientErrorType.METADATA_RETRIEVAL_ERROR
7272
) {
7373
throw new AmplifyUserError(
@@ -81,7 +81,7 @@ export class UnifiedClientConfigGenerator implements ClientConfigGenerator {
8181
);
8282
}
8383
if (
84-
error instanceof BackendOutputClientError &&
84+
BackendOutputClientError.isBackendOutputClientError(error) &&
8585
error.code === BackendOutputClientErrorType.CREDENTIALS_ERROR
8686
) {
8787
throw new AmplifyUserError(
@@ -96,7 +96,7 @@ export class UnifiedClientConfigGenerator implements ClientConfigGenerator {
9696
);
9797
}
9898
if (
99-
error instanceof BackendOutputClientError &&
99+
BackendOutputClientError.isBackendOutputClientError(error) &&
100100
error.code === BackendOutputClientErrorType.ACCESS_DENIED
101101
) {
102102
throw new AmplifyUserError(

packages/deployed-backend-client/API.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ export class BackendOutputClientError extends Error {
8989
constructor(code: BackendOutputClientErrorType, message: string, options?: ErrorOptions);
9090
// (undocumented)
9191
code: BackendOutputClientErrorType;
92+
static isBackendOutputClientError: (error: unknown) => error is BackendOutputClientError;
9293
}
9394

9495
// @public (undocumented)

packages/deployed-backend-client/src/backend_output_client_factory.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,30 @@ export class BackendOutputClientError extends Error {
3131
super(message, options);
3232
this.code = code;
3333
}
34+
35+
/**
36+
* This function is a type predicate for BackendOutputClientError.
37+
* See https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates.
38+
*
39+
* Checks if error is an BackendOutputClientError by inspecting if required properties are set.
40+
* This is recommended instead of instanceof operator.
41+
* The instance of operator does not work as expected if BackendOutputClientError class is loaded
42+
* from multiple sources, for example when package manager decides to not de-duplicate dependencies.
43+
* See https://github.com/nodejs/node/issues/17943.
44+
*/
45+
static isBackendOutputClientError = (
46+
error: unknown
47+
): error is BackendOutputClientError => {
48+
return (
49+
error instanceof Error &&
50+
'code' in error &&
51+
typeof error.code === 'string' &&
52+
(Object.values(BackendOutputClientErrorType) as unknown[]).includes(
53+
error.code
54+
) &&
55+
typeof error.message === 'string'
56+
);
57+
};
3458
}
3559

3660
/**

packages/eslint-rules/src/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@ import { amplifyErrorNameRule } from './rules/amplify_error_name.js';
33
import { preferAmplifyErrorsRule } from './rules/prefer_amplify_errors.js';
44
import { noAmplifyErrors } from './rules/no_amplify_errors.js';
55
import { amplifyErrorNoInstanceOf } from './rules/amplify_error_no_instance_of';
6+
import { backendOutputClientErrorNoInstanceOf } from './rules/backent_output_client_error_no_instance_of.js';
67

78
export const rules: Record<string, unknown> = {
89
'amplify-error-name': amplifyErrorNameRule,
910
'amplify-error-no-instanceof': amplifyErrorNoInstanceOf,
11+
'backend-output-client-error-no-instanceof':
12+
backendOutputClientErrorNoInstanceOf,
1013
'no-empty-catch': noEmptyCatchRule,
1114
'prefer-amplify-errors': preferAmplifyErrorsRule,
1215
'no-amplify-errors': noAmplifyErrors,
@@ -18,6 +21,8 @@ export const configs = {
1821
rules: {
1922
'amplify-backend-rules/amplify-error-name': 'error',
2023
'amplify-backend-rules/amplify-error-no-instanceof': 'error',
24+
'amplify-backend-rules/backend-output-client-error-no-instanceof':
25+
'error',
2126
'amplify-backend-rules/no-empty-catch': 'error',
2227
'amplify-backend-rules/prefer-amplify-errors': 'off',
2328
'amplify-backend-rules/no-amplify-errors': 'off',
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import * as nodeTest from 'node:test';
2+
import { RuleTester } from '@typescript-eslint/rule-tester';
3+
import { backendOutputClientErrorNoInstanceOf } from './backent_output_client_error_no_instance_of';
4+
5+
RuleTester.afterAll = nodeTest.after;
6+
// See https://typescript-eslint.io/packages/rule-tester/#with-specific-frameworks
7+
// Node test runner methods return promises which are not relevant in the context of testing.
8+
// We do ignore them in other places with void keyword.
9+
// eslint-disable-next-line @typescript-eslint/no-misused-promises
10+
RuleTester.it = nodeTest.it;
11+
// eslint-disable-next-line @typescript-eslint/no-misused-promises
12+
RuleTester.describe = nodeTest.describe;
13+
14+
const ruleTester = new RuleTester();
15+
16+
ruleTester.run(
17+
'backend-output-client-error-no-instanceof',
18+
backendOutputClientErrorNoInstanceOf,
19+
{
20+
valid: ['e instanceof Error'],
21+
invalid: [
22+
{
23+
code: 'e instanceof BackendOutputClientError',
24+
errors: [
25+
{
26+
messageId: 'noInstanceOfWithBackendOutputClientError',
27+
},
28+
],
29+
},
30+
],
31+
}
32+
);
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { ESLintUtils } from '@typescript-eslint/utils';
2+
3+
/**
4+
* This rule flags empty catch blocks. Even if they contain comments.
5+
*
6+
* This rule differs from built in https://github.com/eslint/eslint/blob/main/lib/rules/no-empty.js
7+
* in such a way that it uses typescript-eslint and typescript AST
8+
* which does not include comments as statements in catch clause body block.
9+
*/
10+
export const backendOutputClientErrorNoInstanceOf =
11+
ESLintUtils.RuleCreator.withoutDocs({
12+
create(context) {
13+
return {
14+
// This naming comes from @typescript-eslint/utils types.
15+
// eslint-disable-next-line @typescript-eslint/naming-convention
16+
BinaryExpression(node) {
17+
if (
18+
node.operator === 'instanceof' &&
19+
node.right.type === 'Identifier' &&
20+
node.right.name === 'BackendOutputClientError'
21+
) {
22+
context.report({
23+
messageId: 'noInstanceOfWithBackendOutputClientError',
24+
node,
25+
});
26+
}
27+
},
28+
};
29+
},
30+
meta: {
31+
docs: {
32+
description:
33+
'Instanceof operator must not be used with BackendOutputClientError.',
34+
},
35+
messages: {
36+
noInstanceOfWithBackendOutputClientError:
37+
'Do not use instanceof with BackendOutputClientError. Use BackendOutputClientError.isBackendOutputClientError instead.',
38+
},
39+
type: 'problem',
40+
schema: [],
41+
},
42+
defaultOptions: [],
43+
});

packages/model-generator/src/get_backend_output_with_error_handling.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export const getBackendOutputWithErrorHandling = async (
1717
return await backendOutputClient.getOutput(backendIdentifier);
1818
} catch (error) {
1919
if (
20-
error instanceof BackendOutputClientError &&
20+
BackendOutputClientError.isBackendOutputClientError(error) &&
2121
error.code === BackendOutputClientErrorType.DEPLOYMENT_IN_PROGRESS
2222
) {
2323
throw new AmplifyUserError(
@@ -30,7 +30,7 @@ export const getBackendOutputWithErrorHandling = async (
3030
);
3131
}
3232
if (
33-
error instanceof BackendOutputClientError &&
33+
BackendOutputClientError.isBackendOutputClientError(error) &&
3434
error.code === BackendOutputClientErrorType.NO_STACK_FOUND
3535
) {
3636
throw new AmplifyUserError(
@@ -44,7 +44,7 @@ export const getBackendOutputWithErrorHandling = async (
4444
);
4545
}
4646
if (
47-
error instanceof BackendOutputClientError &&
47+
BackendOutputClientError.isBackendOutputClientError(error) &&
4848
error.code === BackendOutputClientErrorType.CREDENTIALS_ERROR
4949
) {
5050
throw new AmplifyUserError(
@@ -58,7 +58,7 @@ export const getBackendOutputWithErrorHandling = async (
5858
);
5959
}
6060
if (
61-
error instanceof BackendOutputClientError &&
61+
BackendOutputClientError.isBackendOutputClientError(error) &&
6262
error.code === BackendOutputClientErrorType.ACCESS_DENIED
6363
) {
6464
throw new AmplifyUserError(

0 commit comments

Comments
 (0)