chore: add directory validation in separate file
This commit is contained in:
parent
94ca584b9e
commit
18680d0a15
@ -194,10 +194,6 @@ func validateContributorAvatarURL(avatarURL *string) []error {
|
||||
return problems
|
||||
}
|
||||
|
||||
func addFilePathToError(filePath string, err error) error {
|
||||
return fmt.Errorf("%q: %v", filePath, err)
|
||||
}
|
||||
|
||||
func validateContributorProfile(yml contributorProfile) []error {
|
||||
allProblems := []error{}
|
||||
|
||||
@ -313,7 +309,6 @@ func aggregateContributorReadmeFiles() ([]readme, error) {
|
||||
for _, e := range dirEntries {
|
||||
dirPath := path.Join(rootRegistryPath, e.Name())
|
||||
if !e.IsDir() {
|
||||
problems = append(problems, fmt.Errorf("detected non-directory file %q at base of main Registry directory", dirPath))
|
||||
continue
|
||||
}
|
||||
|
||||
@ -331,7 +326,7 @@ func aggregateContributorReadmeFiles() ([]readme, error) {
|
||||
|
||||
if len(problems) != 0 {
|
||||
return nil, validationPhaseError{
|
||||
phase: validationPhaseFilesystemRead,
|
||||
phase: validationPhaseFileLoad,
|
||||
errors: problems,
|
||||
}
|
||||
}
|
||||
|
||||
28
cmd/readmevalidation/errors.go
Normal file
28
cmd/readmevalidation/errors.go
Normal file
@ -0,0 +1,28 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
var _ error = validationPhaseError{}
|
||||
|
||||
// validationPhaseError represents an error that occurred during a specific
|
||||
// phase of README validation. It should be used to collect ALL validation
|
||||
// errors that happened during a specific phase, rather than the first one
|
||||
// encountered.
|
||||
type validationPhaseError struct {
|
||||
phase validationPhase
|
||||
errors []error
|
||||
}
|
||||
|
||||
func (vpe validationPhaseError) Error() string {
|
||||
msg := fmt.Sprintf("Error during %q phase of README validation:", vpe.phase.String())
|
||||
for _, e := range vpe.errors {
|
||||
msg += fmt.Sprintf("\n- %v", e)
|
||||
}
|
||||
msg += "\n"
|
||||
|
||||
return msg
|
||||
}
|
||||
|
||||
func addFilePathToError(filePath string, err error) error {
|
||||
return fmt.Errorf("%q: %v", filePath, err)
|
||||
}
|
||||
@ -55,10 +55,17 @@ func main() {
|
||||
} else {
|
||||
log.Println("Provided API token does not belong to a Coder employee. Some README validation steps will be skipped compared to when they run in CI.")
|
||||
}
|
||||
fmt.Printf("actor %q is %s\n", actorUsername, actorOrgStatus.String())
|
||||
fmt.Printf("Script GitHub actor %q has Coder organization status %q\n", actorUsername, actorOrgStatus.String())
|
||||
|
||||
log.Println("Starting README validation")
|
||||
|
||||
// Validate file structure of main README directory
|
||||
err = validateRepoStructure()
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
|
||||
// Validate contributor README files
|
||||
allReadmeFiles, err := aggregateContributorReadmeFiles()
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
@ -75,4 +82,8 @@ func main() {
|
||||
}
|
||||
log.Println("All relative URLs for READMEs are valid")
|
||||
log.Printf("Processed all READMEs in the %q directory\n", rootRegistryPath)
|
||||
|
||||
// Validate modules
|
||||
|
||||
// Validate templates
|
||||
}
|
||||
|
||||
@ -3,7 +3,6 @@ package main
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@ -72,12 +71,15 @@ func separateFrontmatter(readmeText string) (string, string, error) {
|
||||
type validationPhase int
|
||||
|
||||
const (
|
||||
// validationPhaseFilesystemRead indicates when a README file is being read
|
||||
// from the file system
|
||||
validationPhaseFilesystemRead validationPhase = iota
|
||||
//
|
||||
validationPhaseStructureValidation validationPhase = iota
|
||||
|
||||
// validationPhaseReadmeParsing indicates when a README's frontmatter is being
|
||||
// parsed as YAML. This phase does not include YAML validation.
|
||||
// validationPhaseFileLoad indicates when a README file is being read from
|
||||
// the file system
|
||||
validationPhaseFileLoad
|
||||
|
||||
// validationPhaseReadmeParsing indicates when a README's frontmatter is
|
||||
// being parsed as YAML. This phase does not include YAML validation.
|
||||
validationPhaseReadmeParsing
|
||||
|
||||
// validationPhaseReadmeValidation indicates when a README's frontmatter is
|
||||
@ -92,7 +94,7 @@ const (
|
||||
|
||||
func (p validationPhase) String() string {
|
||||
switch p {
|
||||
case validationPhaseFilesystemRead:
|
||||
case validationPhaseFileLoad:
|
||||
return "Filesystem reading"
|
||||
case validationPhaseReadmeParsing:
|
||||
return "README parsing"
|
||||
@ -104,24 +106,3 @@ func (p validationPhase) String() string {
|
||||
return "Unknown validation phase"
|
||||
}
|
||||
}
|
||||
|
||||
var _ error = validationPhaseError{}
|
||||
|
||||
// validationPhaseError represents an error that occurred during a specific
|
||||
// phase of README validation. It should be used to collect ALL validation
|
||||
// errors that happened during a specific phase, rather than the first one
|
||||
// encountered.
|
||||
type validationPhaseError struct {
|
||||
phase validationPhase
|
||||
errors []error
|
||||
}
|
||||
|
||||
func (vpe validationPhaseError) Error() string {
|
||||
msg := fmt.Sprintf("Error during %q phase of README validation:", vpe.phase.String())
|
||||
for _, e := range vpe.errors {
|
||||
msg += fmt.Sprintf("\n- %v", e)
|
||||
}
|
||||
msg += "\n"
|
||||
|
||||
return msg
|
||||
}
|
||||
|
||||
97
cmd/readmevalidation/repostructure.go
Normal file
97
cmd/readmevalidation/repostructure.go
Normal file
@ -0,0 +1,97 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
)
|
||||
|
||||
func validateCoderResourceDirectory(directoryPath string) []error {
|
||||
errs := []error{}
|
||||
|
||||
dir, err := os.Stat(directoryPath)
|
||||
if err != nil {
|
||||
// It's valid for a specific resource directory not to exist. It's just
|
||||
// that if it does exist, it must follow specific rules
|
||||
if !errors.Is(err, os.ErrNotExist) {
|
||||
errs = append(errs, addFilePathToError(directoryPath, err))
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
if !dir.IsDir() {
|
||||
errs = append(errs, fmt.Errorf("%q: path is not a directory", directoryPath))
|
||||
return errs
|
||||
}
|
||||
|
||||
files, err := os.ReadDir(directoryPath)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("%q: %v", directoryPath, err))
|
||||
return errs
|
||||
}
|
||||
for _, f := range files {
|
||||
if !f.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
resourceReadmePath := path.Join(directoryPath, f.Name(), "README.md")
|
||||
_, err := os.Stat(resourceReadmePath)
|
||||
if err == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
errs = append(errs, fmt.Errorf("%q: README file does not exist", resourceReadmePath))
|
||||
} else {
|
||||
errs = append(errs, addFilePathToError(resourceReadmePath, err))
|
||||
}
|
||||
}
|
||||
|
||||
return errs
|
||||
}
|
||||
|
||||
func validateRegistryDirectory() []error {
|
||||
dirEntries, err := os.ReadDir(rootRegistryPath)
|
||||
if err != nil {
|
||||
return []error{err}
|
||||
}
|
||||
|
||||
problems := []error{}
|
||||
for _, e := range dirEntries {
|
||||
dirPath := path.Join(rootRegistryPath, e.Name())
|
||||
if !e.IsDir() {
|
||||
problems = append(problems, fmt.Errorf("detected non-directory file %q at base of main Registry directory", dirPath))
|
||||
continue
|
||||
}
|
||||
|
||||
readmePath := path.Join(dirPath, "README.md")
|
||||
_, err := os.Stat(readmePath)
|
||||
if err != nil {
|
||||
problems = append(problems, err)
|
||||
}
|
||||
|
||||
modulesPath := path.Join(dirPath, "modules")
|
||||
if errs := validateCoderResourceDirectory(modulesPath); len(errs) != 0 {
|
||||
problems = append(problems, errs...)
|
||||
}
|
||||
templatesPath := path.Join(dirPath, "templates")
|
||||
if errs := validateCoderResourceDirectory(templatesPath); len(errs) != 0 {
|
||||
problems = append(problems, errs...)
|
||||
}
|
||||
}
|
||||
|
||||
return problems
|
||||
}
|
||||
|
||||
func validateRepoStructure() error {
|
||||
errs := validateRegistryDirectory()
|
||||
if len(errs) != 0 {
|
||||
return validationPhaseError{
|
||||
phase: validationPhaseFileLoad,
|
||||
errors: errs,
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user