Skip to content

Commit

Permalink
cli: error helper
Browse files Browse the repository at this point in the history
  • Loading branch information
fwang committed Sep 23, 2024
1 parent 51cd27c commit a95974a
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 3 deletions.
12 changes: 12 additions & 0 deletions cmd/sst/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -961,6 +961,18 @@ var root = &cli.Command{
return nil
},
},
{
Name: "common-errors",
Hidden: true,
Run: func(cli *cli.Cli) error {
data, err := json.MarshalIndent(project.CommonErrors, "", " ")
if err != nil {
return err
}
fmt.Println(string(data))
return nil
},
},
{
Name: "refresh",
Description: cli.Description{
Expand Down
4 changes: 4 additions & 0 deletions cmd/sst/mosaic/ui/ui.go
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,10 @@ func (u *UI) Event(unknown interface{}) {
for _, line := range parseError(status.Message) {
u.println(TEXT_NORMAL.Render(" " + line))
}
for i, line := range status.Help {
if i == 0 { u.println() }
u.println(TEXT_NORMAL.Render(" " + line))
}
importDiffs, ok := evt.ImportDiffs[status.URN]
if ok {
isSSTComponent := strings.Contains(status.URN, "::sst")
Expand Down
53 changes: 51 additions & 2 deletions pkg/project/stack.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,49 @@ type StackCommandEvent struct {
}

type Error struct {
Message string `json:"message"`
URN string `json:"urn"`
Message string `json:"message"`
URN string `json:"urn"`
Help []string `json:"help"`
}

type CommonError struct {
Code string `json:"code"`
Message string `json:"message"`
Short []string `json:"short"`
Long []string `json:"long"`
}

var CommonErrors = []CommonError{
{
Code: "TooManyCacheBehaviors",
Message: "TooManyCacheBehaviors: Your request contains more CacheBehaviors than are allowed per distribution",
Short: []string{
"There are too many top-level files and directories inside your app's public asset folder. Move some of them inside subdirectories.",
"Learn more about this https://sst.dev/docs/common-errors#toomanycachebehaviors",
},
Long: []string{
"This error usually happens to SvelteKit, SolidStart, Nuxt, and Analog apps.",
"CloudFront distributions have a limit of 25 cache behaviors per distribution. Each top-level file and directory inside your app's asset folder creates a cache behavior. For example, in the case of a SvelteKit app, the static assets are in the `static` folder. If you have two files in it, it creates 2 cache behaviors.",
"```",
"static/",
"├── favicon.png # Cache behavior for /favicon.png",
"└── logo.png # Cache behavior for /logo.png",
"```",
"If you have too many files, it creates too many cache behaviors and hits the limit.",
"The solution is to move some of the files into subdirectories. For example, by moving the files in the `images` folder, it will only create 1 cache behavior.",
"```",
"static/",
"└── images/ # Cache behavior for /images/*",
" ├── logo.png",
" └── logo.png",
"```",
"Learn more about CloudFront limits [here](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cloudfront-limits.html#limits-web-distributions).",
"Alternatively, you can request a limit increase via the AWS Support.",
},
},
};


var ErrStackRunFailed = fmt.Errorf("stack run had errors")
var ErrStageNotFound = fmt.Errorf("stage not found")
var ErrPassphraseInvalid = fmt.Errorf("passphrase invalid")
Expand Down Expand Up @@ -405,9 +444,19 @@ func (p *Project) Run(ctx context.Context, input *StackInput) error {
if strings.Contains(event.DiagnosticEvent.Message, "failed to register new resource") {
break
}

// check if the error is a common error
help := []string{}
for _, commonError := range CommonErrors {
if strings.Contains(event.DiagnosticEvent.Message, commonError.Message) {
help = append(help, commonError.Short...)
}
}

errors = append(errors, Error{
Message: event.DiagnosticEvent.Message,
URN: event.DiagnosticEvent.URN,
Help: help,
})
telemetry.Track("cli.resource.error", map[string]interface{}{
"error": event.DiagnosticEvent.Message,
Expand Down
2 changes: 2 additions & 0 deletions www/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@ pnpm-debug.log*
.DS_Store

# typedoc output
common-errors-doc.json
components-doc.json
examples-doc.json
cli-doc.json
sdk-doc.json

# generated docs
src/content/docs/docs/common-errors.mdx
src/content/docs/docs/component/
src/content/docs/docs/reference/
!src/content/docs/docs/reference/sdk.mdx
1 change: 1 addition & 0 deletions www/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ const sidebar = [
],
},
{ label: "Examples", slug: "docs/examples" },
{ label: "Common Errors", slug: "docs/common-errors" },
{
label: "Deprecated",
collapsed: true,
Expand Down
101 changes: 101 additions & 0 deletions www/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ type CliCommand = {
children: CliCommand[];
};

type CommonError = {
code: string;
message: string;
long: string[];
};

const cmd = process.argv[2];
const linkHashes = new Map<
TypeDoc.DeclarationReflection,
Expand Down Expand Up @@ -80,6 +86,7 @@ if (!cmd || cmd === "components") {
}
}
if (!cmd || cmd === "cli") await generateCliDoc();
if (!cmd || cmd === "common-errors") await generateCommonErrorsDoc();
if (!cmd || cmd === "examples") await generateExamplesDocs();
restoreCode();

Expand Down Expand Up @@ -301,6 +308,100 @@ function generateCliDoc() {
}
}

function generateCommonErrorsDoc() {
const content = fs.readFileSync("common-errors-doc.json");
const json = JSON.parse(content.toString()) as CommonError[];
const outputFilePath = `src/content/docs/docs/common-errors.mdx`;

fs.writeFileSync(
outputFilePath,
[
renderHeader("Common Errors", "Common errors that SST can report."),
renderSourceMessage("cmd/sst/main.go"),
renderImports(outputFilePath),
renderBodyBegin(),
renderCommonErrorsAbout(),
renderCommonErrorsErrors(),
renderBodyEnd(),
]
.flat()
.join("\n")
);

function renderCommonErrorsAbout() {
return [
`Below are a collection of common errors you might encounter when using SST.`,
"",
":::tip",
"This doc is best viewed through the site search or through the _AI_.",
":::",
"",
"The descriptions for these errors are generated from the CLI.",
"",
];
}

function renderCommonErrorsErrors() {
const lines: string[] = [];

for (const error of json) {
console.debug(` - command ${error.code}`);
lines.push(
``,
`---`,
``,
`## ${error.code}`,
`<Segment>`,
``,
`<Section type="parameters">`,
`> ${error.message}`,
``,
...error.long,
`</Section>`,
`</Segment>`
);
}
return lines;
}

function renderCliDescription(description: CliCommand["description"]) {
return description.long ?? description.short;
}

function renderCliArgName(prop: CliCommand["args"][number]) {
return `${prop.name}${prop.required ? "" : "?"}`;
}

function renderCliCommandUsage(command: CliCommand) {
const parts: string[] = [];

parts.push(command.name);
command.args.forEach((arg) =>
arg.required ? parts.push(`<${arg.name}>`) : parts.push(`[${arg.name}]`)
);
return parts.join(" ");
}

function renderCliFlagType(type: CliCommand["flags"][number]["type"]) {
if (type.startsWith("[") && type.endsWith("]")) {
return type
.substring(1, type.length - 1)
.split(",")
.map((t: string) =>
[
`<code class="symbol">&ldquo;</code>`,
`<code class="primitive">${t}</code>`,
`<code class="symbol">&rdquo;</code>`,
].join("")
)
.join(`<code class="symbol"> | </code>`);
}

if (type === "bool") return `<code class="primitive">boolean</code>`;
return `<code class="primitive">${type}</code>`;
}
}

async function generateExamplesDocs() {
const modules = await buildExamples();
const outputFilePath = `src/content/docs/docs/examples.mdx`;
Expand Down
4 changes: 3 additions & 1 deletion www/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
"generate-components": "tsx generate.ts components",
"generate-examples": "tsx generate.ts examples",
"generate-cli": "bun generate-cli-json && tsx generate.ts cli",
"generate-cli-json": "go run ../cmd/sst introspect > cli-doc.json"
"generate-cli-json": "go run ../cmd/sst introspect > cli-doc.json",
"generate-errors": "bun generate-errors-json && tsx generate.ts common-errors",
"generate-errors-json": "go run ../cmd/sst common-errors > common-errors-doc.json"
},
"dependencies": {
"@astrojs/check": "^0.9.2",
Expand Down

0 comments on commit a95974a

Please sign in to comment.