Skip to content

Commit 3720e4f

Browse files
authored
fix: add guardrail test for unescaped markdown in command descriptions (#549)
* fix: add guardrail test for unescaped markdown in command descriptions The docgen command parses Long descriptions as Go text/template and renders them as MDX for the docs site. Unescaped { characters break the Docusaurus build. This adds a test that walks all commands and validates their descriptions render correctly, catching issues in CI rather than at release time. * style: add comment to docs escape regex in test
1 parent d682c81 commit 3720e4f

2 files changed

Lines changed: 31 additions & 0 deletions

File tree

.claude/CLAUDE.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,10 @@ Use conventional commit format (feat:, fix:, chore:, etc.) for commit titles.
229229
5. Run `slack docgen ./docs/reference` to generate docs
230230
6. Consider adding command alias in `AliasMap` if appropriate
231231

232+
### Command Descriptions and Documentation
233+
234+
Command `Long` descriptions are parsed as Go `text/template` by `docgen` and rendered as MDX for the documentation site. Escape `{` and `[` as `\{` and `\[` in description text to prevent build errors on the docs site. Available template functions: `{{Emoji "name"}}`, `{{LinkText "url"}}`, `{{ToBold "text"}}`.
235+
232236
### Adding New Dependencies
233237

234238
1. Update `go.mod` with the new module version

cmd/root_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"context"
1919
"fmt"
2020
"os"
21+
"regexp"
2122
"strings"
2223
"testing"
2324

@@ -290,3 +291,29 @@ func testExecCmd(ctx context.Context, args []string) (string, error) {
290291
}
291292
return clientsMock.GetCombinedOutput(), nil
292293
}
294+
295+
func Test_CommandDescriptionsRenderForDocs(t *testing.T) {
296+
ctx := slackcontext.MockContext(t.Context())
297+
tmp, _ := os.MkdirTemp("", "")
298+
_ = os.Chdir(tmp)
299+
defer os.RemoveAll(tmp)
300+
301+
cmd, _ := Init(ctx)
302+
303+
// Matches a lone { that is not escaped (\{) and not part of a Go template ({{)
304+
unescapedBrace := regexp.MustCompile(`[^\\{]\{[^{]`)
305+
306+
var walk func(*cobra.Command)
307+
walk = func(c *cobra.Command) {
308+
if c.Long != "" {
309+
t.Run(c.CommandPath(), func(t *testing.T) {
310+
assert.NotRegexp(t, unescapedBrace, c.Long,
311+
"description contains unescaped '{' which breaks the MDX docs site; escape as \\{")
312+
})
313+
}
314+
for _, child := range c.Commands() {
315+
walk(child)
316+
}
317+
}
318+
walk(cmd)
319+
}

0 commit comments

Comments
 (0)