diff --git a/cmd/lint_example_test.go b/cmd/lint_example_test.go index 0b15aac..9fe9814 100644 --- a/cmd/lint_example_test.go +++ b/cmd/lint_example_test.go @@ -8,3 +8,9 @@ func ExampleLint() { // -> The implementation for 'two' is missing a test suite. // -> An implementation for 'zero' was found, but config.json specifies that it should be foregone (not implemented). } + +func ExampleLintMaintainers() { + lintTrack("../fixtures/broken-maintainers") + // Output: + // -> invalid config ../fixtures/broken-maintainers/config/maintainers.json -- invalid character '}' looking for beginning of object key string +} diff --git a/fixtures/broken-maintainers/config.json b/fixtures/broken-maintainers/config.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/fixtures/broken-maintainers/config.json @@ -0,0 +1 @@ +{} diff --git a/fixtures/broken-maintainers/config/maintainers.json b/fixtures/broken-maintainers/config/maintainers.json new file mode 100644 index 0000000..21d7677 --- /dev/null +++ b/fixtures/broken-maintainers/config/maintainers.json @@ -0,0 +1,9 @@ +{ + "maintainers": [ + { + "github_username": "alice", + "show_on_website": false, + } + ], + "docs_url": "http://example.com/docs" +} diff --git a/fixtures/numbers/config/maintainers.json b/fixtures/numbers/config/maintainers.json new file mode 100644 index 0000000..75cdce0 --- /dev/null +++ b/fixtures/numbers/config/maintainers.json @@ -0,0 +1,12 @@ +{ + "maintainers": [ + { + "github_username": "alice", + "show_on_website": false, + "alumnus": false, + "name": "Alice Jones", + "bio": null + } + ], + "docs_url": "http://example.com/docs" +} diff --git a/track/maintainer_config.go b/track/maintainer_config.go new file mode 100644 index 0000000..1d4ad76 --- /dev/null +++ b/track/maintainer_config.go @@ -0,0 +1,47 @@ +package track + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "os" +) + +// MaintainerConfig contains the list of current and previous maintainers. +// The files is used both to manage the GitHub maintainer team, as well +// as to configure the display values for each maintainer on the Exercism +// website. +type MaintainerConfig struct { + Maintainers []Maintainer `json:"maintainers"` + DocsURL string `json:"docs_url"` +} + +// Maintainer contains data about a track maintainer. +type Maintainer struct { + Username string `json:"github_username"` + ShowOnWebsite bool `json:"show_on_website"` + Alumnus bool `json:"alumnus"` + Name string `json:"name"` + Bio string `json:"bio"` + LinkText string `json:"link_text"` + LinkURL string `json:"link_url"` + AvatarURL string `json:"avatar_url"` +} + +// NewMaintainerConfig reads the maintainer config file, if present. +func NewMaintainerConfig(path string) (MaintainerConfig, error) { + mc := MaintainerConfig{} + if _, err := os.Stat(path); os.IsNotExist(err) { + return mc, nil + } + + bytes, err := ioutil.ReadFile(path) + if err != nil { + return mc, err + } + err = json.Unmarshal(bytes, &mc) + if err != nil { + return mc, fmt.Errorf("invalid config %s -- %s", path, err.Error()) + } + return mc, nil +} diff --git a/track/maintainer_config_test.go b/track/maintainer_config_test.go new file mode 100644 index 0000000..37564ae --- /dev/null +++ b/track/maintainer_config_test.go @@ -0,0 +1,26 @@ +package track + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestBrokenMaintainerConfig(t *testing.T) { + if _, err := NewMaintainerConfig("../fixtures/broken-maintainers/config/maintainers.json"); err == nil { + t.Errorf("Expected broken JSON") + } +} + +func TestValidMaintainerConfig(t *testing.T) { + mc, err := NewMaintainerConfig("../fixtures/numbers/config/maintainers.json") + if err != nil { + t.Errorf("Expected valid JSON: %s", err) + } + assert.Equal(t, "alice", mc.Maintainers[0].Username) +} + +func TestIgnoreMissingMaintainerConfig(t *testing.T) { + _, err := NewMaintainerConfig("../fixtures/no-such-file.json") + assert.NoError(t, err) +} diff --git a/track/track.go b/track/track.go index b01fb32..d782f22 100644 --- a/track/track.go +++ b/track/track.go @@ -7,9 +7,10 @@ import ( // Track is a collection of Exercism exercises for a programming language. type Track struct { - path string - Config Config - Exercises []Exercise + path string + Config Config + MaintainerConfig MaintainerConfig + Exercises []Exercise } // New loads a track. @@ -24,6 +25,12 @@ func New(path string) (Track, error) { } track.Config = c + mc, err := NewMaintainerConfig(filepath.Join(path, "config", "maintainers.json")) + if err != nil { + return track, err + } + track.MaintainerConfig = mc + dir := filepath.Join(track.path, "exercises") files, err := ioutil.ReadDir(dir) if err != nil {