Skip to content

Commit 333eb3b

Browse files
retlehsclaude
andcommitted
Generate project README.md during trellis new
Add README generation with project-specific values (site name, host, environment URLs) including Requirements, Local development setup, Deployment, and Documentation sections. Skips if README.md already exists. Closes #11 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent dc6b730 commit 333eb3b

2 files changed

Lines changed: 112 additions & 0 deletions

File tree

cmd/new.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,8 @@ func (c *NewCommand) Run(args []string) int {
188188
return 1
189189
}
190190

191+
c.generateReadme(filepath.Join(path, "README.md"))
192+
191193
fmt.Printf("\n%s project created with versions:\n", color.GreenString(c.name))
192194
fmt.Printf(" Trellis %s\n", trellisRelease.Version)
193195

@@ -318,6 +320,46 @@ func askHost(ui cli.Ui, t *trellis.Trellis, name string) (host string, err error
318320
return result, nil
319321
}
320322

323+
func (c *NewCommand) generateReadme(path string) {
324+
if _, err := os.Stat(path); err == nil {
325+
c.UI.Info("Existing README.md detected, skipping generation.")
326+
return
327+
}
328+
329+
devHost, _ := c.trellis.HostsFromDomain(c.host, "development")
330+
prodHost, _ := c.trellis.HostsFromDomain(c.host, "production")
331+
332+
readme := fmt.Sprintf(`# %s
333+
334+
| Environment | URL |
335+
|-------------|-----|
336+
| Development | http://%s |
337+
| Production | http://%s |
338+
339+
## Requirements
340+
341+
- [trellis-cli](https://github.com/roots/trellis-cli) installed
342+
343+
## Local development setup
344+
345+
1. Clone this repository
346+
2. Run `+"`trellis init`"+` to set up the virtual environment
347+
3. Run `+"`trellis vm start`"+` to start the development server
348+
4. Visit [%s](http://%s)
349+
350+
## Deployment
351+
352+
`+"`"+`$ trellis deploy <environment>`+"`"+`
353+
354+
## Documentation
355+
356+
- [Trellis docs](https://roots.io/trellis/docs/)
357+
- [Bedrock docs](https://roots.io/bedrock/docs/)
358+
`, c.name, devHost, prodHost, devHost, devHost)
359+
360+
os.WriteFile(path, []byte(readme), 0644)
361+
}
362+
321363
func isDirEmpty(name string) (bool, error) {
322364
f, err := os.Open(name)
323365

cmd/new_test.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package cmd
22

33
import (
44
"bytes"
5+
"os"
6+
"path/filepath"
57
"strings"
68
"testing"
79

@@ -126,3 +128,71 @@ func TestAskDomain(t *testing.T) {
126128
})
127129
}
128130
}
131+
132+
func TestGenerateReadme(t *testing.T) {
133+
dir := t.TempDir()
134+
readmePath := filepath.Join(dir, "README.md")
135+
136+
ui := cli.NewMockUi()
137+
tr := trellis.NewMockTrellis(false)
138+
c := NewNewCommand(ui, tr, "1.0.0")
139+
c.name = "example.com"
140+
c.host = "example.com"
141+
142+
c.generateReadme(readmePath)
143+
144+
content, err := os.ReadFile(readmePath)
145+
if err != nil {
146+
t.Fatalf("could not read README.md: %s", err)
147+
}
148+
149+
readme := string(content)
150+
151+
requiredStrings := []string{
152+
"# example.com",
153+
"## Requirements",
154+
"## Local development setup",
155+
"## Documentation",
156+
"http://example.test",
157+
"http://example.com",
158+
"trellis-cli",
159+
"trellis init",
160+
"trellis vm start",
161+
}
162+
163+
for _, s := range requiredStrings {
164+
if !strings.Contains(readme, s) {
165+
t.Errorf("expected README to contain %q", s)
166+
}
167+
}
168+
169+
if strings.Contains(readme, "Vagrant") || strings.Contains(readme, "VirtualBox") {
170+
t.Error("README should not contain Vagrant/VirtualBox references")
171+
}
172+
}
173+
174+
func TestGenerateReadmeSkipsExisting(t *testing.T) {
175+
dir := t.TempDir()
176+
readmePath := filepath.Join(dir, "README.md")
177+
178+
existingContent := "# My custom README\n"
179+
os.WriteFile(readmePath, []byte(existingContent), 0644)
180+
181+
ui := cli.NewMockUi()
182+
tr := trellis.NewMockTrellis(false)
183+
c := NewNewCommand(ui, tr, "1.0.0")
184+
c.name = "example.com"
185+
c.host = "example.com"
186+
187+
c.generateReadme(readmePath)
188+
189+
content, _ := os.ReadFile(readmePath)
190+
if string(content) != existingContent {
191+
t.Errorf("existing README was overwritten: got %q, want %q", string(content), existingContent)
192+
}
193+
194+
combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
195+
if !strings.Contains(combined, "Existing README.md detected") {
196+
t.Error("expected informational message about skipping README generation")
197+
}
198+
}

0 commit comments

Comments
 (0)