-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[CMSP-27] Implement sites.yml parsing (#1)
- Loading branch information
Showing
17 changed files
with
614 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,3 +4,5 @@ | |
.DS_Store | ||
|
||
dist/ | ||
|
||
*.out |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,28 @@ | ||
# Sites.yml | Pantheon.yml Validator | ||
|
||
A utility for validating a sites.yml file on a pantheon site during WordPress multisites' search-replace tasks. Asprirationally to include pantheon.yml validation in the future. | ||
|
||
# Usage | ||
|
||
## Sites.yml | ||
``` | ||
$ pyml-validator sites -f path/to/sites.yml | ||
``` | ||
|
||
See [this annotated fixture](./fixtures/sites/valid.yml) for an example of a valid sites.yml file. | ||
|
||
## Pantheon.yml | ||
Note, validation of pantheon.yml is unimplemented, so any file reads as valid. | ||
``` | ||
$ pyml-validator pantheon -f path/to/pantheon.yml | ||
``` | ||
|
||
# Testing | ||
|
||
[![Coverage Status](https://coveralls.io/repos/github/pantheon-systems/pyml-validator/badge.svg?t=PGhafd)](https://coveralls.io/github/pantheon-systems/pyml-validator) | ||
|
||
`make test` runs linting and testing. | ||
|
||
# Releases | ||
|
||
Automatically releases on merge to main via autotag + goreleaser. See [Autotag Readme](https://github.com/pantheon-systems/autotag) for details on how the SemVer is determined. Note, with goreleaser, each commit merged will become a line item in the release's Changelog. Take note to use squashing and/or rebase to ensure helpful and informative commit messages. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package cmd | ||
|
||
import ( | ||
"log" | ||
|
||
"github.com/spf13/cobra" | ||
) | ||
|
||
var FilePath string | ||
|
||
var rootCmd = &cobra.Command{ | ||
Use: "pyml-validator", | ||
Short: "Pyml-validator validates pantheon.yml, sites.yml, etc.", | ||
Long: `Pyml-validator is a validator for pantheon.yml or sites.yml. | ||
Ensures that the given config file can be used by the platform.`, | ||
} | ||
|
||
func Execute() { | ||
if err := rootCmd.Execute(); err != nil { | ||
log.Fatal(err) | ||
} | ||
} | ||
|
||
func init() { | ||
rootCmd.PersistentFlags().StringVarP(&FilePath, "file", "f", "", "path/to/file.yml") | ||
err := rootCmd.MarkPersistentFlagRequired("file") | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package cmd | ||
|
||
import ( | ||
"fmt" | ||
"pyml-validator/pkg/validator" | ||
|
||
"github.com/spf13/cobra" | ||
) | ||
|
||
func validatorCommand(cmd *cobra.Command) error { | ||
// Is there a better way to do this? Without this we print usage on error exits. | ||
// If we override at the root level, we don't get usage when we _do_ want it. | ||
cmd.SilenceUsage = true | ||
|
||
v, err := validator.ValidatorFactory(cmd.Use) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
err = v.ValidateFromFilePath(FilePath) | ||
if err != nil { | ||
return err | ||
} | ||
fmt.Printf("✨ %s.yml is valid\n", cmd.Use) | ||
return nil | ||
} | ||
|
||
var sitesCommand = &cobra.Command{ | ||
Use: "sites", | ||
Short: "validate sites.yml", | ||
Long: `Validate sites.yml`, | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
return validatorCommand(cmd) | ||
}, | ||
} | ||
|
||
var pantheonCommand = &cobra.Command{ | ||
Use: "pantheon", | ||
Short: "validate pantheon.yml", | ||
Long: `Validate pantheon.yml. For more information, see https://pantheon.io/docs/pantheon-yml`, | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
return validatorCommand(cmd) | ||
}, | ||
} | ||
|
||
func init() { | ||
rootCmd.AddCommand(pantheonCommand) | ||
rootCmd.AddCommand(sitesCommand) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
--- | ||
api_version: 2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
--- | ||
api_version: 1 # Currently only one api version. | ||
|
||
# "domain_maps" is a collection of blog URLs for each environment used to | ||
# facilitate search-replace of a WordPress Multisite (WPMS) across pantheon | ||
# environments. Each key of "domain_maps" must be a valid environment name. | ||
domain_maps: | ||
# environment: <collection of domains to be used on this environment> | ||
# i.e. dev, test, live, feat-branch, &c. | ||
dev: | ||
# each environment collection maps the blog ID to its URL. A url must be | ||
# set in both the target and source environments for search-replace to be | ||
# run. | ||
# i.e. 1: blog1-mysite.com | ||
1: about.dev-mysite.pantheonsite.io | ||
2: employee-resources.dev-mysite.pantheonsite.io | ||
3: staff-portal.dev-mysite.pantheonsite.io | ||
test: | ||
1: about.test-mysite.pantheonsite.io | ||
2: employee-resources.test-mysite.pantheonsite.io | ||
3: staff-portal.test-mysite.pantheonsite.io | ||
live: | ||
1: about.mysite.com | ||
2: employee-resources.mysite.com | ||
3: staff-portal.mysite.com | ||
autopilot: | ||
1: about.autopilot-mysite.pantheonsite.io | ||
2: employee-resources.autopilot-mysite.pantheonsite.io | ||
3: staff-portal.autopilot-mysite.pantheonsite.io | ||
|
||
# Anything else in the file will be ignored, but not rejected. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
--- | ||
api_version: 1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,18 @@ | ||
module pyml-validator | ||
|
||
go 1.19 | ||
|
||
require ( | ||
github.com/spf13/cobra v1.6.1 | ||
github.com/stretchr/testify v1.8.1 | ||
gopkg.in/yaml.v3 v3.0.1 | ||
) | ||
|
||
require ( | ||
github.com/davecgh/go-spew v1.1.1 // indirect | ||
github.com/inconshreveable/mousetrap v1.1.0 // indirect | ||
github.com/pmezard/go-difflib v1.0.0 // indirect | ||
github.com/spf13/pflag v1.0.5 // indirect | ||
) | ||
|
||
replace gopkg.in/yaml.v3 => gopkg.in/yaml.v3 v3.0.1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= | ||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= | ||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= | ||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= | ||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= | ||
github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= | ||
github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= | ||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= | ||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= | ||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= | ||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= | ||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= | ||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= | ||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,7 @@ | ||
package main | ||
|
||
func main() {} | ||
import "pyml-validator/cmd" | ||
|
||
func main() { | ||
cmd.Execute() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package model | ||
|
||
// SitesYml is used to map domains across environments for search and replace with WPMS sites. | ||
type SitesYml struct { | ||
APIVersion int `yaml:"api_version"` | ||
DomainMaps DomainMaps `yaml:"domain_maps"` | ||
} | ||
|
||
type DomainMaps map[string]DomainMapByEnvironment | ||
|
||
// DomainMapByEnvironment is a map of site (blog) domains keyed by blog ID. | ||
type DomainMapByEnvironment map[int]string |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package validator | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
) | ||
|
||
type PantheonValidator struct{} | ||
|
||
// ValidateFromYaml asserts a given pantheon.yaml file is valid. | ||
// As this has not been implemented, nothing is invalid. | ||
func (v *PantheonValidator) ValidateFromYaml(y []byte) error { | ||
return nil | ||
} | ||
|
||
func (v *PantheonValidator) ValidateFromFilePath(filePath string) error { | ||
yFile, err := os.ReadFile(filePath) | ||
if err != nil { | ||
return fmt.Errorf("error reading YAML file: %w", err) | ||
} | ||
return v.ValidateFromYaml(yFile) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
package validator | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"pyml-validator/pkg/model" | ||
"regexp" | ||
|
||
"gopkg.in/yaml.v3" | ||
) | ||
|
||
const ( | ||
MaxDomainMaps = 25 // This could be raised | ||
) | ||
|
||
var ( | ||
// See https://github.com/pantheon-systems/titan-mt/blob/master/yggdrasil/lib/pantheon_yml/pantheon_yml_v1_schema.py | ||
ValidHostnameRegex = regexp.MustCompile(`^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$`) | ||
ValidMultidevNameRegex = regexp.MustCompile(`^[a-z0-9\-]{1,11}$`) | ||
) | ||
|
||
type SitesValidator struct{} | ||
|
||
// ValidateFromYaml asserts a given sites.yaml file is valid. | ||
func (v *SitesValidator) ValidateFromYaml(y []byte) error { | ||
var s model.SitesYml | ||
|
||
err := yaml.Unmarshal(y, &s) | ||
if err != nil { | ||
return err | ||
} | ||
return v.validate(s) | ||
} | ||
|
||
func (v *SitesValidator) ValidateFromFilePath(filePath string) error { | ||
yFile, err := os.ReadFile(filePath) | ||
if err != nil { | ||
return fmt.Errorf("error reading YAML file: %w", err) | ||
} | ||
return v.ValidateFromYaml(yFile) | ||
} | ||
|
||
// validate asserts all aspects of sites.yml are valid. | ||
func (v *SitesValidator) validate(sites model.SitesYml) error { | ||
err := validateAPIVersion(sites.APIVersion) | ||
if err != nil { | ||
return err | ||
} | ||
return validateDomainMaps(sites.DomainMaps) | ||
} | ||
|
||
// validateDomainMaps ensures the domain maps provided in sites.yml are valid | ||
// by asserting cloud development environments names are valid, there are not | ||
// too many domain maps listed for any environment, and that the hostnames | ||
// provided are valid Pantheon hostnames. | ||
func validateDomainMaps(domainMaps map[string]model.DomainMapByEnvironment) error { | ||
for env, domainMap := range domainMaps { | ||
if !ValidMultidevNameRegex.MatchString(env) { | ||
return fmt.Errorf("%q is not a valid environment name", env) | ||
} | ||
domainMapCount := len(domainMap) | ||
if domainMapCount > MaxDomainMaps { | ||
return fmt.Errorf("%q has too many domains listed (%d). Maximum is %d", env, domainMapCount, MaxDomainMaps) | ||
} | ||
for _, domain := range domainMap { | ||
if !ValidHostnameRegex.MatchString(domain) { | ||
return fmt.Errorf("%q is not a valid hostname", domain) | ||
} | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
// validateAPIVersion asserts if sites.yml has a valid api version set. Once | ||
// more than one version is valid, this will need to be more more robust. | ||
func validateAPIVersion(apiVersion int) error { | ||
if apiVersion != 1 { | ||
return ErrInvalidAPIVersion | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package validator | ||
|
||
import "errors" | ||
|
||
var ( | ||
ErrInvalidAPIVersion = errors.New("Invalid API Version. Must be '1'") | ||
) | ||
|
||
// TODO: More dynamic errors could be refactored here, but likely only worth | ||
// pursuing once we are passing errors back to customers |
Oops, something went wrong.