mirror of
https://github.com/coder/coder.git
synced 2026-10-16 14:48:56 +08:00
## Problem Template builder base READMEs delimit their prerequisites section with HTML comment markers (`<!-- prerequisites:start -->` / `<!-- prerequisites:end -->`). `ExtractPrerequisites` uses these to populate the builder's Prerequisites step, which works correctly. However, `Compose` embeds the **full** base README verbatim into the generated template's tarball. Because `react-markdown` renders raw HTML comments as literal text, the markers were visible when the delivered README is viewed via `MemoizedMarkdown`. <img width="876" height="586" alt="Screenshot 2026-09-03 at 3 28 08 PM" src="https://github.com/user-attachments/assets/70353ee2-1ff6-4e70-9b5d-7ac0521b945f" /> ## Fix Strip the prerequisite markers from the README before writing it into the tarball (Option 2), keeping the change contained to the template builder and leaving global markdown rendering untouched. - `prerequisites.go`: new `StripPrerequisiteMarkers` removes each marker line (plus an optional trailing blank line so no gap is left) while preserving the content between them. - `compose.go`: new `composedReadme` helper applies the strip in both `Compose` return paths; returns `nil` for an empty README, preserving the existing "omit README.md when empty" behavior. - `ExtractPrerequisites` still reads the markers from the source `BaseReadme`, so the builder's Prerequisites step is unaffected. ## Testing - `TestStripPrerequisiteMarkers` covers both markers, no markers, single markers, missing trailing blank line, and end-of-file cases. - Extended the compose test to assert the delivered README contains no marker text. - `go test ./coderd/templatebuilder/`, `go vet`, and `golangci-lint run ./coderd/templatebuilder/...` all pass. <details> <summary>Approach considered</summary> Two options were on the table: 1. Skip HTML comments in the shared `MemoizedMarkdown` component (fixes any stray comment globally, but changes shared rendering behavior app-wide). 2. Strip the markers from the README before inserting it into the template zipball (targeted; markers have no purpose in the delivered README since prerequisites are already extracted separately). Option 2 was chosen for being contained and easily unit-tested. </details> --- _This PR was created by Coder Agents on behalf of @jeremyruppel._ --------- Co-authored-by: Andrew Aquino <dawneraq@gmail.com>
143 lines
3.4 KiB
Go
143 lines
3.4 KiB
Go
package templatebuilder_test
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/coder/coder/v2/coderd/templatebuilder"
|
|
)
|
|
|
|
func TestExtractPrerequisites(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
readme string
|
|
expected string
|
|
}{
|
|
{
|
|
name: "BothMarkers",
|
|
readme: "# Title\n\n" +
|
|
"<!-- prerequisites:start -->\n" +
|
|
"## Prerequisites\n\n" +
|
|
"Install Docker.\n" +
|
|
"<!-- prerequisites:end -->\n\n" +
|
|
"## Architecture\n",
|
|
expected: "## Prerequisites\n\nInstall Docker.",
|
|
},
|
|
{
|
|
name: "MultipleH2Sections",
|
|
readme: "# Title\n\n" +
|
|
"<!-- prerequisites:start -->\n" +
|
|
"## Prerequisites\n\n" +
|
|
"Auth stuff.\n\n" +
|
|
"## Required permissions\n\n" +
|
|
"Policy JSON.\n" +
|
|
"<!-- prerequisites:end -->\n\n" +
|
|
"## Architecture\n",
|
|
expected: "## Prerequisites\n\nAuth stuff.\n\n## Required permissions\n\nPolicy JSON.",
|
|
},
|
|
{
|
|
name: "NoMarkers",
|
|
readme: "# Title\n\n## Prerequisites\n\nSome content.\n\n## Architecture\n",
|
|
expected: "",
|
|
},
|
|
{
|
|
name: "StartMarkerOnly",
|
|
readme: "# Title\n\n" +
|
|
"<!-- prerequisites:start -->\n" +
|
|
"## Prerequisites\n\nContent.\n",
|
|
expected: "",
|
|
},
|
|
{
|
|
name: "EndMarkerOnly",
|
|
readme: "# Title\n\n" +
|
|
"## Prerequisites\n\nContent.\n" +
|
|
"<!-- prerequisites:end -->\n",
|
|
expected: "",
|
|
},
|
|
{
|
|
name: "EmptyBetweenMarkers",
|
|
readme: "<!-- prerequisites:start -->\n" +
|
|
"<!-- prerequisites:end -->\n",
|
|
expected: "",
|
|
},
|
|
{
|
|
name: "NestedH3Headings",
|
|
readme: "<!-- prerequisites:start -->\n" +
|
|
"## Prerequisites\n\n" +
|
|
"### Infrastructure\n\n" +
|
|
"Docker socket required.\n\n" +
|
|
"### Authentication\n\n" +
|
|
"Use kubeconfig.\n" +
|
|
"<!-- prerequisites:end -->\n",
|
|
expected: "## Prerequisites\n\n### Infrastructure\n\nDocker socket required.\n\n### Authentication\n\nUse kubeconfig.",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
result := templatebuilder.ExtractPrerequisites(tt.readme)
|
|
require.Equal(t, tt.expected, result)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestStripPrerequisitesMarkers(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
readme string
|
|
expected string
|
|
}{
|
|
{
|
|
name: "BothMarkers",
|
|
readme: "# Title\n\n" +
|
|
"<!-- prerequisites:start -->\n\n" +
|
|
"## Prerequisites\n\n" +
|
|
"Install Docker.\n\n" +
|
|
"<!-- prerequisites:end -->\n\n" +
|
|
"## Architecture\n",
|
|
expected: "# Title\n\n## Prerequisites\n\nInstall Docker.\n\n## Architecture\n",
|
|
},
|
|
{
|
|
name: "NoMarkers",
|
|
readme: "# Title\n\n## Prerequisites\n\nSome content.\n",
|
|
expected: "# Title\n\n## Prerequisites\n\nSome content.\n",
|
|
},
|
|
{
|
|
name: "StartMarkerOnly",
|
|
readme: "# Title\n\n" +
|
|
"<!-- prerequisites:start -->\n\n" +
|
|
"## Prerequisites\n",
|
|
expected: "# Title\n\n## Prerequisites\n",
|
|
},
|
|
{
|
|
name: "MarkerWithoutTrailingBlankLine",
|
|
readme: "# Title\n" +
|
|
"<!-- prerequisites:start -->\n" +
|
|
"## Prerequisites\n",
|
|
expected: "# Title\n## Prerequisites\n",
|
|
},
|
|
{
|
|
name: "EndMarkerAtEOF",
|
|
readme: "Content.\n\n" +
|
|
"<!-- prerequisites:end -->\n",
|
|
expected: "Content.\n\n",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
result := templatebuilder.StripPrerequisitesMarkers(tt.readme)
|
|
require.Equal(t, tt.expected, result)
|
|
require.NotContains(t, result, "prerequisites:start")
|
|
require.NotContains(t, result, "prerequisites:end")
|
|
})
|
|
}
|
|
}
|