Skip to content

Commit b567f6d

Browse files
Merge branch 'main' into feat-codex-cli
2 parents 82ff539 + 08ed594 commit b567f6d

File tree

14 files changed

+464
-189
lines changed

14 files changed

+464
-189
lines changed

cmd/readmevalidation/codermodules.go

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
package main
2+
3+
import (
4+
"bufio"
5+
"context"
6+
"strings"
7+
8+
"golang.org/x/xerrors"
9+
)
10+
11+
func validateCoderModuleReadmeBody(body string) []error {
12+
var errs []error
13+
14+
trimmed := strings.TrimSpace(body)
15+
if baseErrs := validateReadmeBody(trimmed); len(baseErrs) != 0 {
16+
errs = append(errs, baseErrs...)
17+
}
18+
19+
foundParagraph := false
20+
terraformCodeBlockCount := 0
21+
foundTerraformVersionRef := false
22+
23+
lineNum := 0
24+
isInsideCodeBlock := false
25+
isInsideTerraform := false
26+
27+
lineScanner := bufio.NewScanner(strings.NewReader(trimmed))
28+
for lineScanner.Scan() {
29+
lineNum++
30+
nextLine := lineScanner.Text()
31+
32+
// Code assumes that invalid headers would've already been handled by the base validation function, so we don't
33+
// need to check deeper if the first line isn't an h1.
34+
if lineNum == 1 {
35+
if !strings.HasPrefix(nextLine, "# ") {
36+
break
37+
}
38+
continue
39+
}
40+
41+
if strings.HasPrefix(nextLine, "```") {
42+
isInsideCodeBlock = !isInsideCodeBlock
43+
isInsideTerraform = isInsideCodeBlock && strings.HasPrefix(nextLine, "```tf")
44+
if isInsideTerraform {
45+
terraformCodeBlockCount++
46+
}
47+
if strings.HasPrefix(nextLine, "```hcl") {
48+
errs = append(errs, xerrors.New("all hcl code blocks must be converted to tf"))
49+
}
50+
continue
51+
}
52+
53+
if isInsideCodeBlock {
54+
if isInsideTerraform {
55+
foundTerraformVersionRef = foundTerraformVersionRef || terraformVersionRe.MatchString(nextLine)
56+
}
57+
continue
58+
}
59+
60+
// Code assumes that we can treat this case as the end of the "h1 section" and don't need to process any further lines.
61+
if lineNum > 1 && strings.HasPrefix(nextLine, "#") {
62+
break
63+
}
64+
65+
// Code assumes that if we've reached this point, the only other options are:
66+
// (1) empty spaces, (2) paragraphs, (3) HTML, and (4) asset references made via [] syntax.
67+
trimmedLine := strings.TrimSpace(nextLine)
68+
isParagraph := trimmedLine != "" && !strings.HasPrefix(trimmedLine, "![") && !strings.HasPrefix(trimmedLine, "<")
69+
foundParagraph = foundParagraph || isParagraph
70+
}
71+
72+
if terraformCodeBlockCount == 0 {
73+
errs = append(errs, xerrors.New("did not find Terraform code block within h1 section"))
74+
} else {
75+
if terraformCodeBlockCount > 1 {
76+
errs = append(errs, xerrors.New("cannot have more than one Terraform code block in h1 section"))
77+
}
78+
if !foundTerraformVersionRef {
79+
errs = append(errs, xerrors.New("did not find Terraform code block that specifies 'version' field"))
80+
}
81+
}
82+
if !foundParagraph {
83+
errs = append(errs, xerrors.New("did not find paragraph within h1 section"))
84+
}
85+
if isInsideCodeBlock {
86+
errs = append(errs, xerrors.New("code blocks inside h1 section do not all terminate before end of file"))
87+
}
88+
89+
return errs
90+
}
91+
92+
func validateCoderModuleReadme(rm coderResourceReadme) []error {
93+
var errs []error
94+
for _, err := range validateCoderModuleReadmeBody(rm.body) {
95+
errs = append(errs, addFilePathToError(rm.filePath, err))
96+
}
97+
if fmErrs := validateCoderResourceFrontmatter("modules", rm.filePath, rm.frontmatter); len(fmErrs) != 0 {
98+
errs = append(errs, fmErrs...)
99+
}
100+
return errs
101+
}
102+
103+
func validateAllCoderModuleReadmes(resources []coderResourceReadme) error {
104+
var yamlValidationErrors []error
105+
for _, readme := range resources {
106+
errs := validateCoderModuleReadme(readme)
107+
if len(errs) > 0 {
108+
yamlValidationErrors = append(yamlValidationErrors, errs...)
109+
}
110+
}
111+
if len(yamlValidationErrors) != 0 {
112+
return validationPhaseError{
113+
phase: validationPhaseReadme,
114+
errors: yamlValidationErrors,
115+
}
116+
}
117+
return nil
118+
}
119+
120+
func validateAllCoderModules() error {
121+
const resourceType = "modules"
122+
allReadmeFiles, err := aggregateCoderResourceReadmeFiles(resourceType)
123+
if err != nil {
124+
return err
125+
}
126+
127+
logger.Info(context.Background(), "processing template README files", "resource_type", resourceType, "num_files", len(allReadmeFiles))
128+
resources, err := parseCoderResourceReadmeFiles(resourceType, allReadmeFiles)
129+
if err != nil {
130+
return err
131+
}
132+
err = validateAllCoderModuleReadmes(resources)
133+
if err != nil {
134+
return err
135+
}
136+
logger.Info(context.Background(), "processed README files as valid Coder resources", "resource_type", resourceType, "num_files", len(resources))
137+
138+
if err := validateCoderResourceRelativeURLs(resources); err != nil {
139+
return err
140+
}
141+
logger.Info(context.Background(), "all relative URLs for READMEs are valid", "resource_type", resourceType)
142+
return nil
143+
}

cmd/readmevalidation/coderresources_test.go renamed to cmd/readmevalidation/codermodules_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ func TestValidateCoderResourceReadmeBody(t *testing.T) {
1414
t.Run("Parses a valid README body with zero issues", func(t *testing.T) {
1515
t.Parallel()
1616

17-
errs := validateCoderResourceReadmeBody(testBody)
17+
errs := validateCoderModuleReadmeBody(testBody)
1818
for _, e := range errs {
1919
t.Error(e)
2020
}

0 commit comments

Comments
 (0)