Skip to content

Commit

Permalink
Add YAML configuration (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
krzysztofreczek authored Nov 19, 2020
1 parent cd283c2 commit c3c51a0
Show file tree
Hide file tree
Showing 10 changed files with 271 additions and 13 deletions.
54 changes: 51 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,14 @@ type Info struct {

### Scraper

Scraper may be instantiated in one of two ways:
* from the code
* from the YAML file

In order to instantiate the scraper you need to provide scraper configuration which contains a slice of prefixes of packages that you want to reflect. Types that do not match any of the given prefixes will not be traversed.
```go
config := scraper.NewConfiguration(
"github.com/karhoo/svc-billing",
"github.com/krzysztofreczek/pkg",
)
s := scraper.NewScraper(config)
```
Expand All @@ -41,15 +45,37 @@ Each rule consists of:
* Apply function - function that produces `model.Info` describing the component included in the scraped structure

```go
r, _ := scraper.NewRule().
r, err := scraper.NewRule().
WithPkgRegexps("github.com/krzysztofreczek/pkg/foo/.*").
WithNameRegexp("^(.*)Client$").
WithApplyFunc(
func() model.Info {
return model.ComponentInfo("foo client", "client of a foo service", "TAG")
}).
Build()
_ = s.RegisterRule(r)
err = s.RegisterRule(r)
```

Alternatively, you can instantiate the scraper form YAML configuration file:
```yaml
// go-structurizr.yml
configuration:
pkgs:
- "github.com/krzysztofreczek/pkg"

rules:
- name_regexp: "^(.*)Client$"
pkg_regexps:
- "github.com/krzysztofreczek/pkg/foo/.*"
component:
description: "foo client"
technology: "client of a foo service"
tags:
- TAG
```
```go
s, err := scraper.NewScraperFromConfigFile("./go-structurizr.yml")
```

Eventually, having the scraper instantiated and configured you can use it to scrape any structure you want. Scraper returns a struct `model.Structure`.
Expand All @@ -59,6 +85,10 @@ structure := s.Scrap(app)

### View

Similarly to the scraper, view may be instantiated in one of two ways:
* from the code
* from the YAML file

In order to render scraped structure, you will need to instantiate and configure a view.
View consists of:
* title
Expand All @@ -73,6 +103,7 @@ v := view.NewView().Build()
In case you need to customize it, use available builder methods:
```go
v := view.NewView().
WithTitle("Title")
WithComponentStyle(
view.NewComponentStyle("TAG").
WithBackgroundColor(color.White).
Expand All @@ -82,6 +113,23 @@ v := view.NewView().
Build()
```

Alternatively, you can instantiate the view form YAML configuration file:
```yaml
// go-structurizr.yml
view:
title: "Title"
line_color: 000000ff
styles:
- id: TAG
background_color: ffffffff
font_color: 000000ff
border_color: 000000ff
```
```go
v, err := view.NewViewFromConfigFile("./go-structurizr.yml")
```

As the view is initialized, you can now render the structure into planUML diagram.
```go
outFile, _ := os.Create("c4.plantuml")
Expand Down
5 changes: 4 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@ module github.com/krzysztofreczek/go-structurizr

go 1.15

require github.com/pkg/errors v0.9.1
require (
github.com/pkg/errors v0.9.1
gopkg.in/yaml.v2 v2.3.0
)
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
1 change: 0 additions & 1 deletion pkg/scraper/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,3 @@ func NewConfiguration(packages ...string) Configuration {
packages: packages,
}
}

25 changes: 23 additions & 2 deletions pkg/scraper/scraper.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package scraper

import (
"errors"
"fmt"
"hash/fnv"
"reflect"
"strings"
"unsafe"

"github.com/krzysztofreczek/go-structurizr/pkg/model"
"github.com/krzysztofreczek/go-structurizr/pkg/yaml"
"github.com/pkg/errors"
)

type Scraper struct {
Expand All @@ -25,6 +26,27 @@ func NewScraper(config Configuration) *Scraper {
}
}

func NewScraperFromConfigFile(fileName string) (*Scraper, error) {
configuration, err := yaml.LoadFromFile(fileName)
if err != nil {
return nil, errors.Wrapf(err,
"could not load configuration from file `%s`", fileName)
}

config := toScraperConfig(configuration)
rules, err := toScraperRules(configuration)
if err != nil {
return nil, errors.Wrapf(err,
"could not load scraper rules from from configuration file `%s`", fileName)
}

return &Scraper{
config: config,
rules: rules,
structure: model.NewStructure(),
}, nil
}

func (s *Scraper) RegisterRule(r Rule) error {
if r == nil {
return errors.New("rule must not be nil")
Expand Down Expand Up @@ -67,7 +89,6 @@ func (s *Scraper) scrap(
for i := 0; i < v.Len(); i++ {
s.scrap(v.Index(i), parentID, level)
}
return
}

v = normalize(v)
Expand Down
40 changes: 40 additions & 0 deletions pkg/scraper/yaml.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package scraper

import (
"github.com/krzysztofreczek/go-structurizr/pkg/model"
"github.com/krzysztofreczek/go-structurizr/pkg/yaml"
)

func toScraperConfig(c yaml.Config) Configuration {
return NewConfiguration(c.Configuration.Packages...)
}

func toScraperRules(c yaml.Config) ([]Rule, error) {
rules := make([]Rule, len(c.Rules))
for i, r := range c.Rules {
r := r
rule, err := NewRule().
WithNameRegexp(r.NameRegexp).
WithPkgRegexps(r.PackageRegexps...).
WithApplyFunc(
func() model.Info {
info := make([]string, len(r.Component.Tags)+2)
info[0] = r.Component.Description
info[1] = r.Component.Technology

idx := 2
for _, t := range r.Component.Tags {
info[idx] = t
idx++
}

return model.ComponentInfo(info...)
},
).Build()
if err != nil {
return nil, err
}
rules[i] = rule
}
return rules, nil
}
10 changes: 5 additions & 5 deletions pkg/view/snippets.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,9 @@ func buildSkinParamRectangle(
) string {
s := snippetSkinParamRectangle
s = strings.Replace(s, paramRectangleName, name, -1)
s = strings.Replace(s, paramBackgroundColor, hex(backgroundColor), -1)
s = strings.Replace(s, paramFontColor, hex(fontColor), -1)
s = strings.Replace(s, paramBorderColor, hex(borderColor), -1)
s = strings.Replace(s, paramBackgroundColor, toHex(backgroundColor), -1)
s = strings.Replace(s, paramFontColor, toHex(fontColor), -1)
s = strings.Replace(s, paramBorderColor, toHex(borderColor), -1)
return s
}

Expand Down Expand Up @@ -118,11 +118,11 @@ func buildComponentConnection(
s := snippetComponentConnection
s = strings.Replace(s, paramComponentIDFrom, fromID, -1)
s = strings.Replace(s, paramComponentIDTo, toID, -1)
s = strings.Replace(s, paramLineColor, hex(lineColor), -1)
s = strings.Replace(s, paramLineColor, toHex(lineColor), -1)
return s
}

func hex(c color.Color) string {
func toHex(c color.Color) string {
rgba := color.RGBAModel.Convert(c).(color.RGBA)
return fmt.Sprintf("#%.2x%.2x%.2x", rgba.R, rgba.G, rgba.B)
}
23 changes: 22 additions & 1 deletion pkg/view/view.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package view

import "image/color"
import (
"image/color"

"github.com/krzysztofreczek/go-structurizr/pkg/yaml"
"github.com/pkg/errors"
)

type View struct {
title string
Expand Down Expand Up @@ -34,6 +39,22 @@ func NewView() *Builder {
}
}

func NewViewFromConfigFile(fileName string) (View, error) {
configuration, err := yaml.LoadFromFile(fileName)
if err != nil {
return View{}, errors.Wrapf(err,
"could not load configuration from file `%s`", fileName)
}

v, err := toView(configuration)
if err != nil {
return View{}, errors.Wrapf(err,
"could not load view from file `%s`", fileName)
}

return v, nil
}

func (b *Builder) WithTitle(t string) *Builder {
b.title = t
return b
Expand Down
62 changes: 62 additions & 0 deletions pkg/view/yaml.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package view

import (
"encoding/hex"
"image/color"
"log"

"github.com/krzysztofreczek/go-structurizr/pkg/yaml"
)

func toView(c yaml.Config) (View, error) {
v := NewView().WithTitle(c.View.Title)

if c.View.LineColor != "" {
col, err := decodeHexColor(c.View.LineColor)
if err != nil {
return View{}, err
}
v.WithLineColor(col)
}

for _, s := range c.View.Styles {
style := NewComponentStyle(s.ID)

if s.BackgroundColor != "" {
col, err := decodeHexColor(s.BackgroundColor)
if err != nil {
return View{}, err
}
style.WithBackgroundColor(col)
}

if s.FontColor != "" {
col, err := decodeHexColor(s.FontColor)
if err != nil {
return View{}, err
}
style.WithFontColor(col)
}

if s.BorderColor != "" {
col, err := decodeHexColor(s.BorderColor)
if err != nil {
return View{}, err
}
style.WithBorderColor(col)
}

v.WithComponentStyle(style.Build())
}

return v.Build(), nil
}

func decodeHexColor(s string) (color.Color, error) {
b, err := hex.DecodeString(s)
if err != nil {
log.Fatal(err)
}

return color.RGBA{R: b[0], G: b[1], B: b[2], A: 255}, nil
}
Loading

0 comments on commit c3c51a0

Please sign in to comment.