Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: wraps no outputs found error from backend output client #2368

Merged
merged 1 commit into from
Dec 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/chilly-pillows-live.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@aws-amplify/model-generator': patch
'@aws-amplify/client-config': patch
'@aws-amplify/sandbox': patch
'@aws-amplify/backend-cli': patch
---

wraps no outputs found error from backend output client
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,60 @@ void describe('generate forms command', () => {
);
});

void it('throws user error if the stack outputs are undefined', async () => {
const fakeSandboxId = 'my-fake-app-my-fake-username';
const backendIdResolver = {
resolveDeployedBackendIdentifier: mock.fn(() =>
Promise.resolve({
namespace: fakeSandboxId,
name: fakeSandboxId,
type: 'sandbox',
})
),
resolveBackendIdentifier: mock.fn(() =>
Promise.resolve({
namespace: fakeSandboxId,
name: fakeSandboxId,
type: 'sandbox',
})
),
} as BackendIdentifierResolver;
const formGenerationHandler = new FormGenerationHandler({
awsClientProvider,
});

const fakedBackendOutputClient = {
getOutput: mock.fn(() => {
throw new BackendOutputClientError(
BackendOutputClientErrorType.NO_OUTPUTS_FOUND,
'stack outputs are undefined'
);
}),
};

const generateFormsCommand = new GenerateFormsCommand(
backendIdResolver,
() => fakedBackendOutputClient,
formGenerationHandler
);

const parser = yargs().command(
generateFormsCommand as unknown as CommandModule
);
const commandRunner = new TestCommandRunner(parser);
await assert.rejects(
() => commandRunner.runCommand('forms'),
(error: TestCommandError) => {
assert.strictEqual(error.error.name, 'AmplifyOutputsNotFoundError');
assert.strictEqual(
error.error.message,
'Amplify outputs not found in stack metadata'
);
return true;
}
);
});

void it('throws user error if credentials are expired when getting backend outputs', async () => {
const fakeSandboxId = 'my-fake-app-my-fake-username';
const backendIdResolver = {
Expand Down
114 changes: 57 additions & 57 deletions packages/cli/src/commands/generate/forms/generate_forms_command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,64 +82,64 @@ export class GenerateFormsCommand
try {
output = await backendOutputClient.getOutput(backendIdentifier);
} catch (error) {
if (
BackendOutputClientError.isBackendOutputClientError(error) &&
error.code === BackendOutputClientErrorType.DEPLOYMENT_IN_PROGRESS
) {
throw new AmplifyUserError(
'DeploymentInProgressError',
{
message: 'Deployment is currently in progress.',
resolution: 'Re-run this command once the deployment completes.',
},
error
);
if (BackendOutputClientError.isBackendOutputClientError(error)) {
switch (error.code) {
case BackendOutputClientErrorType.DEPLOYMENT_IN_PROGRESS:
throw new AmplifyUserError(
'DeploymentInProgressError',
{
message: 'Deployment is currently in progress.',
resolution:
'Re-run this command once the deployment completes.',
},
error
);
case BackendOutputClientErrorType.NO_STACK_FOUND:
throw new AmplifyUserError(
'StackDoesNotExistError',
{
message: 'Stack does not exist.',
resolution:
'Ensure the CloudFormation stack ID or Amplify App ID and branch specified are correct and exists, then re-run this command.',
},
error
);
case BackendOutputClientErrorType.NO_OUTPUTS_FOUND:
throw new AmplifyUserError(
'AmplifyOutputsNotFoundError',
{
message: 'Amplify outputs not found in stack metadata',
resolution: `Ensure the CloudFormation stack ID or Amplify App ID and branch specified are correct and exists.
If this is a new sandbox or branch deployment, wait for the deployment to be successfully finished and try again.`,
},
error
);
case BackendOutputClientErrorType.CREDENTIALS_ERROR:
throw new AmplifyUserError(
'CredentialsError',
{
message:
'Unable to get backend outputs due to invalid credentials.',
resolution:
'Ensure your AWS credentials are correctly set and refreshed.',
},
error
);
case BackendOutputClientErrorType.ACCESS_DENIED:
throw new AmplifyUserError(
'AccessDeniedError',
{
message:
'Unable to get backend outputs due to insufficient permissions.',
resolution:
'Ensure you have permissions to call cloudformation:GetTemplateSummary.',
},
error
);
default:
throw error;
}
}
if (
BackendOutputClientError.isBackendOutputClientError(error) &&
error.code === BackendOutputClientErrorType.NO_STACK_FOUND
) {
throw new AmplifyUserError(
'StackDoesNotExistError',
{
message: 'Stack does not exist.',
resolution:
'Ensure the CloudFormation stack ID or Amplify App ID and branch specified are correct and exists, then re-run this command.',
},
error
);
}
if (
BackendOutputClientError.isBackendOutputClientError(error) &&
error.code === BackendOutputClientErrorType.CREDENTIALS_ERROR
) {
throw new AmplifyUserError(
'CredentialsError',
{
message:
'Unable to get backend outputs due to invalid credentials.',
resolution:
'Ensure your AWS credentials are correctly set and refreshed.',
},
error
);
}
if (
BackendOutputClientError.isBackendOutputClientError(error) &&
error.code === BackendOutputClientErrorType.ACCESS_DENIED
) {
throw new AmplifyUserError(
'AccessDeniedError',
{
message:
'Unable to get backend outputs due to insufficient permissions.',
resolution:
'Ensure you have permissions to call cloudformation:GetTemplateSummary.',
},
error
);
}

throw error;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,39 @@ void describe('UnifiedClientConfigGenerator', () => {
);
});

void it('throws user error if the stack outputs are undefined', async () => {
const outputRetrieval = mock.fn(() => {
throw new BackendOutputClientError(
BackendOutputClientErrorType.NO_OUTPUTS_FOUND,
'stack outputs are undefined'
);
});
const modelSchemaAdapter = new ModelIntrospectionSchemaAdapter(
stubClientProvider
);

const configContributors = new ClientConfigContributorFactory(
modelSchemaAdapter
).getContributors('1.3');

const clientConfigGenerator = new UnifiedClientConfigGenerator(
outputRetrieval,
configContributors
);

await assert.rejects(
() => clientConfigGenerator.generateClientConfig(),
(error: AmplifyUserError) => {
assert.strictEqual(
error.message,
'Amplify outputs not found in stack metadata'
);
assert.ok(error.resolution);
return true;
}
);
});

void it('throws user error if the stack is missing metadata', async () => {
const outputRetrieval = mock.fn(() => {
throw new BackendOutputClientError(
Expand Down
136 changes: 65 additions & 71 deletions packages/client-config/src/unified_client_config_generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,78 +39,72 @@ export class UnifiedClientConfigGenerator implements ClientConfigGenerator {
try {
output = await this.fetchOutput();
} catch (error) {
if (
BackendOutputClientError.isBackendOutputClientError(error) &&
error.code === BackendOutputClientErrorType.DEPLOYMENT_IN_PROGRESS
) {
throw new AmplifyUserError(
'DeploymentInProgressError',
{
message: 'Deployment is currently in progress.',
resolution: 'Re-run this command once the deployment completes.',
},
error
);
}
if (
BackendOutputClientError.isBackendOutputClientError(error) &&
error.code === BackendOutputClientErrorType.NO_STACK_FOUND
) {
throw new AmplifyUserError(
'StackDoesNotExistError',
{
message: 'Stack does not exist.',
resolution:
'Ensure the CloudFormation stack ID or Amplify App ID and branch specified are correct and exists, then re-run this command.',
},
error
);
}
if (
BackendOutputClientError.isBackendOutputClientError(error) &&
error.code === BackendOutputClientErrorType.METADATA_RETRIEVAL_ERROR
) {
throw new AmplifyUserError(
'NonAmplifyStackError',
{
message: 'Stack was not created with Amplify.',
resolution:
'Ensure the CloudFormation stack ID references a main stack created with Amplify, then re-run this command.',
},
error
);
}
if (
BackendOutputClientError.isBackendOutputClientError(error) &&
error.code === BackendOutputClientErrorType.CREDENTIALS_ERROR
) {
throw new AmplifyUserError(
'CredentialsError',
{
message:
'Unable to get backend outputs due to invalid credentials.',
resolution:
'Ensure your AWS credentials are correctly set and refreshed.',
},
error
);
}
if (
BackendOutputClientError.isBackendOutputClientError(error) &&
error.code === BackendOutputClientErrorType.ACCESS_DENIED
) {
throw new AmplifyUserError(
'AccessDeniedError',
{
message:
'Unable to get backend outputs due to insufficient permissions.',
resolution:
'Ensure you have permissions to call cloudformation:GetTemplateSummary.',
},
error
);
if (BackendOutputClientError.isBackendOutputClientError(error)) {
switch (error.code) {
case BackendOutputClientErrorType.DEPLOYMENT_IN_PROGRESS:
throw new AmplifyUserError(
'DeploymentInProgressError',
{
message: 'Deployment is currently in progress.',
resolution:
'Re-run this command once the deployment completes.',
},
error
);
case BackendOutputClientErrorType.NO_STACK_FOUND:
throw new AmplifyUserError(
'StackDoesNotExistError',
{
message: 'Stack does not exist.',
resolution:
'Ensure the CloudFormation stack ID or Amplify App ID and branch specified are correct and exists, then re-run this command.',
},
error
);
case BackendOutputClientErrorType.METADATA_RETRIEVAL_ERROR:
throw new AmplifyUserError(
'NonAmplifyStackError',
{
message: 'Stack was not created with Amplify.',
resolution:
'Ensure the CloudFormation stack ID references a main stack created with Amplify, then re-run this command.',
},
error
);
case BackendOutputClientErrorType.NO_OUTPUTS_FOUND:
throw new AmplifyUserError(
'AmplifyOutputsNotFoundError',
{
message: 'Amplify outputs not found in stack metadata',
resolution: `Ensure the CloudFormation stack ID or Amplify App ID and branch specified are correct and exists.
If this is a new sandbox or branch deployment, wait for the deployment to be successfully finished and try again.`,
},
error
);
case BackendOutputClientErrorType.CREDENTIALS_ERROR:
throw new AmplifyUserError(
'CredentialsError',
{
message:
'Unable to get backend outputs due to invalid credentials.',
resolution:
'Ensure your AWS credentials are correctly set and refreshed.',
},
error
);
case BackendOutputClientErrorType.ACCESS_DENIED:
throw new AmplifyUserError(
'AccessDeniedError',
{
message:
'Unable to get backend outputs due to insufficient permissions.',
resolution:
'Ensure you have permissions to call cloudformation:GetTemplateSummary.',
},
error
);
}
}

throw error;
}
const backendOutput = unifiedBackendOutputSchema.parse(output);
Expand Down
Loading
Loading