11package main
22
33import (
4- "bufio"
5- "context"
64 "errors"
75 "net/url"
86 "os"
@@ -89,7 +87,7 @@ func validateCoderResourceIconURL(iconURL string) []error {
8987 return []error {xerrors .New ("icon URL cannot be empty" )}
9088 }
9189
92- errs := []error {}
90+ var errs []error
9391
9492 // If the URL does not have a relative path.
9593 if ! strings .HasPrefix (iconURL , "." ) && ! strings .HasPrefix (iconURL , "/" ) {
@@ -120,7 +118,7 @@ func validateCoderResourceTags(tags []string) error {
120118
121119 // All of these tags are used for the module/template filter controls in the Registry site. Need to make sure they
122120 // can all be placed in the browser URL without issue.
123- invalidTags := []string {}
121+ var invalidTags []string
124122 for _ , t := range tags {
125123 if t != url .QueryEscape (t ) {
126124 invalidTags = append (invalidTags , t )
@@ -133,108 +131,27 @@ func validateCoderResourceTags(tags []string) error {
133131 return nil
134132}
135133
136- func validateCoderResourceReadmeBody (body string ) []error {
137- var errs []error
138-
139- trimmed := strings .TrimSpace (body )
140- // TODO: this may cause unexpected behavior since the errors slice may have a 0 length. Add a test.
141- errs = append (errs , validateReadmeBody (trimmed )... )
142-
143- foundParagraph := false
144- terraformCodeBlockCount := 0
145- foundTerraformVersionRef := false
146-
147- lineNum := 0
148- isInsideCodeBlock := false
149- isInsideTerraform := false
150-
151- lineScanner := bufio .NewScanner (strings .NewReader (trimmed ))
152- for lineScanner .Scan () {
153- lineNum ++
154- nextLine := lineScanner .Text ()
155-
156- // Code assumes that invalid headers would've already been handled by the base validation function, so we don't
157- // need to check deeper if the first line isn't an h1.
158- if lineNum == 1 {
159- if ! strings .HasPrefix (nextLine , "# " ) {
160- break
161- }
162- continue
163- }
164-
165- if strings .HasPrefix (nextLine , "```" ) {
166- isInsideCodeBlock = ! isInsideCodeBlock
167- isInsideTerraform = isInsideCodeBlock && strings .HasPrefix (nextLine , "```tf" )
168- if isInsideTerraform {
169- terraformCodeBlockCount ++
170- }
171- if strings .HasPrefix (nextLine , "```hcl" ) {
172- errs = append (errs , xerrors .New ("all .hcl language references must be converted to .tf" ))
173- }
174- continue
175- }
176-
177- if isInsideCodeBlock {
178- if isInsideTerraform {
179- foundTerraformVersionRef = foundTerraformVersionRef || terraformVersionRe .MatchString (nextLine )
180- }
181- continue
182- }
183-
184- // Code assumes that we can treat this case as the end of the "h1 section" and don't need to process any further lines.
185- if lineNum > 1 && strings .HasPrefix (nextLine , "#" ) {
186- break
187- }
188-
189- // Code assumes that if we've reached this point, the only other options are:
190- // (1) empty spaces, (2) paragraphs, (3) HTML, and (4) asset references made via [] syntax.
191- trimmedLine := strings .TrimSpace (nextLine )
192- isParagraph := trimmedLine != "" && ! strings .HasPrefix (trimmedLine , "![" ) && ! strings .HasPrefix (trimmedLine , "<" )
193- foundParagraph = foundParagraph || isParagraph
194- }
195-
196- if terraformCodeBlockCount == 0 {
197- errs = append (errs , xerrors .New ("did not find Terraform code block within h1 section" ))
198- } else {
199- if terraformCodeBlockCount > 1 {
200- errs = append (errs , xerrors .New ("cannot have more than one Terraform code block in h1 section" ))
201- }
202- if ! foundTerraformVersionRef {
203- errs = append (errs , xerrors .New ("did not find Terraform code block that specifies 'version' field" ))
204- }
205- }
206- if ! foundParagraph {
207- errs = append (errs , xerrors .New ("did not find paragraph within h1 section" ))
208- }
209- if isInsideCodeBlock {
210- errs = append (errs , xerrors .New ("code blocks inside h1 section do not all terminate before end of file" ))
134+ func validateCoderResourceFrontmatter (resourceType string , filePath string , fm coderResourceFrontmatter ) []error {
135+ if ! slices .Contains (supportedResourceTypes , resourceType ) {
136+ return []error {xerrors .Errorf ("cannot process unknown resource type %q" , resourceType )}
211137 }
212138
213- return errs
214- }
215-
216- func validateCoderResourceReadme (rm coderResourceReadme ) []error {
217139 var errs []error
218-
219- for _ , err := range validateCoderResourceReadmeBody (rm .body ) {
220- errs = append (errs , addFilePathToError (rm .filePath , err ))
221- }
222-
223- if err := validateCoderResourceDisplayName (rm .frontmatter .DisplayName ); err != nil {
224- errs = append (errs , addFilePathToError (rm .filePath , err ))
140+ if err := validateCoderResourceDisplayName (fm .DisplayName ); err != nil {
141+ errs = append (errs , addFilePathToError (filePath , err ))
225142 }
226- if err := validateCoderResourceDescription (rm . frontmatter .Description ); err != nil {
227- errs = append (errs , addFilePathToError (rm . filePath , err ))
143+ if err := validateCoderResourceDescription (fm .Description ); err != nil {
144+ errs = append (errs , addFilePathToError (filePath , err ))
228145 }
229- if err := validateCoderResourceTags (rm . frontmatter .Tags ); err != nil {
230- errs = append (errs , addFilePathToError (rm . filePath , err ))
146+ if err := validateCoderResourceTags (fm .Tags ); err != nil {
147+ errs = append (errs , addFilePathToError (filePath , err ))
231148 }
232149
233- for _ , err := range validateCoderResourceIconURL (rm . frontmatter .IconURL ) {
234- errs = append (errs , addFilePathToError (rm . filePath , err ))
150+ for _ , err := range validateCoderResourceIconURL (fm .IconURL ) {
151+ errs = append (errs , addFilePathToError (filePath , err ))
235152 }
236- for _ , err := range validateSupportedOperatingSystems (rm . frontmatter .OperatingSystems ) {
237- errs = append (errs , addFilePathToError (rm . filePath , err ))
153+ for _ , err := range validateSupportedOperatingSystems (fm .OperatingSystems ) {
154+ errs = append (errs , addFilePathToError (filePath , err ))
238155 }
239156
240157 return errs
@@ -248,7 +165,7 @@ func parseCoderResourceReadme(resourceType string, rm readme) (coderResourceRead
248165
249166 keyErrs := validateFrontmatterYamlKeys (fm , supportedCoderResourceStructKeys )
250167 if len (keyErrs ) != 0 {
251- remapped := []error {}
168+ var remapped []error
252169 for _ , e := range keyErrs {
253170 remapped = append (remapped , addFilePathToError (rm .filePath , e ))
254171 }
@@ -268,7 +185,11 @@ func parseCoderResourceReadme(resourceType string, rm readme) (coderResourceRead
268185 }, nil
269186}
270187
271- func parseCoderResourceReadmeFiles (resourceType string , rms []readme ) (map [string ]coderResourceReadme , error ) {
188+ func parseCoderResourceReadmeFiles (resourceType string , rms []readme ) ([]coderResourceReadme , error ) {
189+ if ! slices .Contains (supportedResourceTypes , resourceType ) {
190+ return nil , xerrors .Errorf ("cannot process unknown resource type %q" , resourceType )
191+ }
192+
272193 resources := map [string ]coderResourceReadme {}
273194 var yamlParsingErrs []error
274195 for _ , rm := range rms {
@@ -287,30 +208,27 @@ func parseCoderResourceReadmeFiles(resourceType string, rms []readme) (map[strin
287208 }
288209 }
289210
290- yamlValidationErrors := []error {}
291- for _ , readme := range resources {
292- errs := validateCoderResourceReadme (readme )
293- if len (errs ) > 0 {
294- yamlValidationErrors = append (yamlValidationErrors , errs ... )
295- }
211+ var serialized []coderResourceReadme
212+ for _ , r := range resources {
213+ serialized = append (serialized , r )
296214 }
297- if len (yamlValidationErrors ) != 0 {
298- return nil , validationPhaseError {
299- phase : validationPhaseReadme ,
300- errors : yamlValidationErrors ,
301- }
302- }
303-
304- return resources , nil
215+ slices .SortFunc (serialized , func (r1 coderResourceReadme , r2 coderResourceReadme ) int {
216+ return strings .Compare (r1 .filePath , r2 .filePath )
217+ })
218+ return serialized , nil
305219}
306220
307221// Todo: Need to beef up this function by grabbing each image/video URL from
308222// the body's AST.
309- func validateCoderResourceRelativeURLs (_ map [ string ]coderResourceReadme ) error {
223+ func validateCoderResourceRelativeURLs (_ [ ]coderResourceReadme ) error {
310224 return nil
311225}
312226
313227func aggregateCoderResourceReadmeFiles (resourceType string ) ([]readme , error ) {
228+ if ! slices .Contains (supportedResourceTypes , resourceType ) {
229+ return nil , xerrors .Errorf ("cannot process unknown resource type %q" , resourceType )
230+ }
231+
314232 registryFiles , err := os .ReadDir (rootRegistryPath )
315233 if err != nil {
316234 return nil , err
@@ -359,27 +277,3 @@ func aggregateCoderResourceReadmeFiles(resourceType string) ([]readme, error) {
359277 }
360278 return allReadmeFiles , nil
361279}
362-
363- func validateAllCoderResourceFilesOfType (resourceType string ) error {
364- if ! slices .Contains (supportedResourceTypes , resourceType ) {
365- return xerrors .Errorf ("resource type %q is not part of supported list [%s]" , resourceType , strings .Join (supportedResourceTypes , ", " ))
366- }
367-
368- allReadmeFiles , err := aggregateCoderResourceReadmeFiles (resourceType )
369- if err != nil {
370- return err
371- }
372-
373- logger .Info (context .Background (), "processing README files" , "num_files" , len (allReadmeFiles ))
374- resources , err := parseCoderResourceReadmeFiles (resourceType , allReadmeFiles )
375- if err != nil {
376- return err
377- }
378- logger .Info (context .Background (), "processed README files as valid Coder resources" , "num_files" , len (resources ), "type" , resourceType )
379-
380- if err := validateCoderResourceRelativeURLs (resources ); err != nil {
381- return err
382- }
383- logger .Info (context .Background (), "all relative URLs for READMEs are valid" , "type" , resourceType )
384- return nil
385- }
0 commit comments