Skip to content

Commit

Permalink
Fix problems with handling apps with namespaces (#58)
Browse files Browse the repository at this point in the history
  • Loading branch information
orlade-anz committed Sep 29, 2020
1 parent 1453a0d commit 318f79e
Show file tree
Hide file tree
Showing 9 changed files with 270 additions and 30 deletions.
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
.PHONY: install lint test
.PHONY: install lint tidy test test-integration coverage
all: lint test install demo
install:
go install github.com/anz-bank/sysl-catalog
lint:
golangci-lint run ./...
tidy:
go mod tidy
gofmt -s -w .
goimports -w .
coverage:
go test -coverprofile=coverage.txt -covermode=atomic ./... && go tool cover -func=coverage.txt
test:
Expand Down
12 changes: 5 additions & 7 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ require (
github.com/Masterminds/sprig v2.22.0+incompatible
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38
github.com/anz-bank/mermaid-go v0.1.1
github.com/anz-bank/pkg v0.0.22
github.com/anz-bank/pkg v0.0.25
github.com/anz-bank/protoc-gen-sysl v0.0.17
github.com/anz-bank/sysl v0.207.0
github.com/anz-bank/sysl v0.223.0
github.com/cheggaaa/pb/v3 v3.0.4
github.com/getkin/kin-openapi v0.18.0 // indirect
github.com/go-chi/chi v4.1.2+incompatible // indirect
Expand All @@ -19,17 +19,15 @@ require (
github.com/hashicorp/go-retryablehttp v0.6.6
github.com/huandu/xstrings v1.3.2 // indirect
github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334
github.com/imdario/mergo v0.3.9 // indirect
github.com/mitchellh/copystructure v1.0.0 // indirect
github.com/mitchellh/reflectwalk v1.0.1 // indirect
github.com/pkg/errors v0.9.1
github.com/radovskyb/watcher v1.0.7
github.com/sirupsen/logrus v1.6.0
github.com/spf13/afero v1.3.5
github.com/spf13/afero v1.4.0
github.com/stretchr/testify v1.6.1
github.com/yuin/goldmark v1.1.31
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 // indirect
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
github.com/yuin/goldmark v1.1.32
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43
google.golang.org/protobuf v1.25.0
gopkg.in/alecthomas/kingpin.v2 v2.2.6
gopkg.in/src-d/go-git.v4 v4.13.1
Expand Down
150 changes: 148 additions & 2 deletions go.sum

Large diffs are not rendered by default.

36 changes: 30 additions & 6 deletions pkg/catalog/diagram.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ func (p *Generator) CreateMarkdown(t *template.Template, outputFileName string,
return nil
}
func (p *Generator) CreateIntegrationDiagram(m *sysl.Module, title string, EPA bool) string {
defer func() {
if err := recover(); err != nil {
p.Log.Errorf("error creating integration diagram: %s", err)
}
}()
if p.Mermaid {
return p.CreateIntegrationDiagramMermaid(m, title, EPA)
}
Expand Down Expand Up @@ -138,6 +143,11 @@ func (p *Generator) CreateIntegrationDiagramPlantuml(m *sysl.Module, title strin
}

func (p *Generator) CreateSequenceDiagram(appName string, endpoint *sysl.Endpoint) string {
defer func() {
if err := recover(); err != nil {
p.Log.Errorf("error creating sequence diagram: %s", err)
}
}()
if p.Mermaid {
return p.CreateSequenceDiagramMermaid(appName, endpoint)
}
Expand Down Expand Up @@ -174,6 +184,11 @@ type Param interface {

// CreateParamDataModel creates a parameter data model and returns a filename
func (p *Generator) CreateParamDataModel(app *sysl.Application, param Param) string {
defer func() {
if err := recover(); err != nil {
p.Log.Errorf("error creating param data model: %s", err)
}
}()
var appName, typeName, aliasTypeName string
var getRecursive bool
aliasTypeName = param.GetName()
Expand Down Expand Up @@ -224,7 +239,7 @@ func (p *Generator) GetReturnType(endpoint *sysl.Endpoint, stmnt *sysl.Statement
typeName = split[0]
}
if appName == "" {
appName = strings.Join(endpoint.GetSource().GetPart(), "")
appName = JoinAppNameString(endpoint.GetSource())
}
return p.RootModule.GetApps()[appName].GetTypes()[typeName]
}
Expand Down Expand Up @@ -283,6 +298,11 @@ func (p *Generator) CreateReturnDataModel(appname string, stmnt *sysl.Statement,
// CreateTypeDiagram creates a data model diagram and returns the filename
// It handles recursively getting the related types, or for primitives, just returns the
func (p *Generator) CreateTypeDiagram(appName string, typeName string, t *sysl.Type, recursive bool) string {
defer func() {
if err := recover(); err != nil {
p.Log.Errorf("error creating type diagram: %s", err)
}
}()
if p.Mermaid {
return p.CreateAliasedTypeDiagramMermaid(appName, typeName, typeName, recursive)
}
Expand Down Expand Up @@ -320,6 +340,7 @@ func (p *Generator) CreateAliasedTypeDiagram(appName, typeName, typeAlias string
)
plantumlString = catalogdiagrams.GenerateDataModel(appName, relatedTypes)
if _, ok := p.RootModule.GetApps()[appName]; !ok {
p.Log.Warnf("no app named %s", appName)
return ""
}
// Handle Empty
Expand All @@ -332,8 +353,10 @@ func (p *Generator) CreateAliasedTypeDiagram(appName, typeName, typeAlias string
map[string]*catalogdiagrams.TypeData{typeAlias: catalogdiagrams.NewTypeData(typeAlias, t)},
)
}
appNameParts := strings.Split(appName, " :: ")
dirname := appNameParts[len(appNameParts)-1]
return p.CreateFile(
plantumlString, plantuml, appName,
plantumlString, plantuml, dirname,
typeName+TernaryOperator(
recursive,
TernaryOperator(typeAlias == typeName, "", typeAlias),
Expand Down Expand Up @@ -447,12 +470,13 @@ func (p *Generator) CreateFile(contents string, diagramType int, elems ...string

// GenerateDataModel generates a data model for all of the types in app
func (p *Generator) GenerateDataModel(app *sysl.Application) string {
appName := strings.Join(app.GetName().GetPart(), "")
appName := GetAppNameString(app)
filename := strings.ReplaceAll(appName, " :: ", "")
plantumlString := catalogdiagrams.GenerateDataModel(appName, catalogdiagrams.FromSyslTypeMap(appName, app.GetTypes()))
if _, ok := p.RootModule.GetApps()[appName]; !ok {
return ""
}
return p.CreateFile(plantumlString, plantuml, appName, "types"+p.Ext)
return p.CreateFile(plantumlString, plantuml, filename, "types"+p.Ext)
}

func (p *Generator) getProjectApp(m *sysl.Module) (*sysl.Application, map[string]string) {
Expand Down Expand Up @@ -512,7 +536,7 @@ func (p *Generator) ModuleAsMacroPackage(m *sysl.Module) map[string]*sysl.Module
if _, ok := packages[projectEndpoint]; !ok {
packages[projectEndpoint] = &sysl.Module{Apps: map[string]*sysl.Application{}}
}
packages[projectEndpoint].GetApps()[strings.Join(app.GetName().GetPart(), "")] = app
packages[projectEndpoint].GetApps()[GetAppNameString(app)] = app
}
return packages
}
Expand Down Expand Up @@ -581,7 +605,7 @@ func (p *Generator) ModuleAsPackages(m *sysl.Module) map[string]*sysl.Module {
if _, ok := packages[packageName]; !ok {
packages[packageName] = &sysl.Module{Apps: map[string]*sysl.Application{}}
}
packages[packageName].GetApps()[strings.Join(app.GetName().GetPart(), "")] = app
packages[packageName].GetApps()[GetAppNameString(app)] = app
}
return packages
}
26 changes: 26 additions & 0 deletions pkg/catalog/diagram_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,32 @@ func TestCreateTypeDiagramWithRecursiveSequenceTypes(t *testing.T) {
)
}

func TestCreateTypeDiagramWithRecursiveNamespacedSequenceTypes(t *testing.T) {
//TODO: do sequence of aliased and non-aliased primitives, and sequence of self
filePath := "../../tests/namespaced_seq_type.sysl"
outputDir := "test"
fs := afero.NewOsFs()
logger := logrus.New()
m, _, err := loader.LoadSyslModule("", filePath, fs, logger)
if err != nil {
t.Fatal(err)
}
p := NewProject(filePath, plantumlService, "markdown", logger, m, afero.NewMemMapFs(), outputDir)
fileStringSequenceRef := p.CreateTypeDiagram("First :: App", "VeryComplex", m.Apps["First :: App"].Types["VeryComplex"], true)
assert.Equal(t, "App/verycomplex.svg", fileStringSequenceRef)
assert.Equal(t,
"http://plantuml.com/plantuml/svg/~1UDgCaS5Bmp0KX-_lh_ZPIpMQqbr3AIjB52yBQFHQIXOqq7KroK2H_UyoDiM3IBxRWu_tFNZBc8QGzjkHocoeB975MUsUZBvJQ_NG6IMnqbA1SqYDjJPGyjvS_AZPMxDl9JiECQ9uTk5ZjTlEetilC4JqDPe6b_9c5-ohtrpXreUO80IwUQv-sMXRVD8reZ-E0GACFRgtlPkiGsDFKiiO7RvJP_EKMVoNiNyb811JyDCB7QYlmJX7KLSLAz0lQEccpV5RNm400F__RwXdH000",
p.FilesToCreate[path.Join(outputDir, fileStringSequenceRef)],
)

fileStringSequenceRef = p.CreateTypeDiagram("Second :: App2", "KindaComplex", m.Apps["Second :: App2"].Types["KindaComplex"], true)
assert.Equal(t, "App2/kindacomplex.svg", fileStringSequenceRef)
assert.Equal(t,
"http://plantuml.com/plantuml/svg/~1UDgCab5hip0KXk_pAzxF6xzbKwoN8b9fiZ465LQtMv4Oje2DBiV2njX_7qMxjMKRdZlboVEUDsH9G-s6tRPb_knXlezPCw7vGrdSoBMypqifi2g4H11055WN9QIuBVzzeREjitTbggs9uBMQQDLj-rQ_UgW9LOGqnNznrJdrR9eBN1j70v84UT-7ZzgzJJIo3E_i4cJsdmu9ED_ebvssIYDL8vHnpZuEKHCvnYp-Yb4_HI013SxOfs_ZdR5DVR9zVARTQDNPPlB6uV61W_te1ivA_5PzR5L5u440Bmf3xg5Qi2e--H6nfRRD_Wbz1W00__-iqvJ7",
p.FilesToCreate[path.Join(outputDir, fileStringSequenceRef)],
)
}

func TestCreateReturnDataModelWithEmpty(t *testing.T) {
filePath := "../../tests/return.sysl"
outputDir := "test"
Expand Down
20 changes: 18 additions & 2 deletions pkg/catalog/generator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,22 @@ var testFiles = []string{
"test/integrationepa.svg",
}

type AferoRetriever struct {
fs afero.Fs
}

func (ar AferoRetriever) Retrieve(resource string) ([]byte, bool, error) {
f, err := ar.fs.Open(resource)
if err != nil {
return nil, false, err
}
bs, err := ioutil.ReadAll(f)
if err != nil {
return nil, false, err
}
return bs, false, nil
}

func TestNewProjectWithLoadSyslModule(t *testing.T) {
filePath := "../../tests/params.sysl"
outputDir := "test"
Expand Down Expand Up @@ -66,7 +82,7 @@ func TestNewProjectWithParser(t *testing.T) {
filePath := "../../tests/params.sysl"
outputDir := "test"
fs := afero.NewMemMapFs()
m, err := parse.NewParser().Parse(filePath, afero.NewOsFs())
m, err := parse.NewParser().Parse(filePath, AferoRetriever{afero.NewOsFs()})
if err != nil {
log.Fatal(err)
}
Expand Down Expand Up @@ -133,7 +149,7 @@ whatever:

func TestNewProjectFromJson(t *testing.T) {

expectedModule, err := parse.NewParser().Parse("../../tests/rest.sysl", afero.NewOsFs())
expectedModule, err := parse.NewParser().Parse("../../tests/rest.sysl", AferoRetriever{afero.NewOsFs()})
require.Nil(t, err)

expected := NewProject("", "", "", logrus.New(), expectedModule, afero.NewMemMapFs(), "/")
Expand Down
21 changes: 15 additions & 6 deletions pkg/catalog/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,9 @@ func NewTypeRef(appName, typeName string) *sysl.Type {
return &sysl.Type{
Type: &sysl.Type_TypeRef{
TypeRef: &sysl.ScopedRef{
Ref: &sysl.Scope{Appname: &sysl.AppName{
Part: []string{appName},
},
Path: []string{appName, typeName},
Ref: &sysl.Scope{
Appname: &sysl.AppName{Part: []string{appName}},
Path: []string{typeName},
},
},
},
Expand Down Expand Up @@ -181,9 +180,19 @@ type Namer interface {
GetName() *sysl.AppName
}

// GetAppNameString returns an app's name as a string, with the namespace joined on "::".
func GetAppNameString(a Namer) string {
return JoinAppNameString(a.GetName())
}

// JoinAppNameString transforms an AppName to a string, with the namespace joined on "::".
func JoinAppNameString(an *sysl.AppName) string {
return strings.Join(an.GetPart(), " :: ")
}

// GetAppPackageName returns the package and app name of any sysl application
func GetAppPackageName(a Namer) (string, string) {
appName := strings.Join(a.GetName().GetPart(), "")
appName := GetAppNameString(a)
packageName := appName
if attr := a.GetAttrs()["package"]; attr != nil {
packageName = attr.GetS()
Expand Down Expand Up @@ -385,7 +394,7 @@ func GetAppTypeName(param Typer) (appName string, typeName string) {
if len(appNameParts) > 0 {
typeNameParts := ref.GetPath()
if typeNameParts != nil {
appName = appNameParts[0]
appName = JoinAppNameString(ref.GetAppname())
typeName = typeNameParts[0]
} else {
typeName = appNameParts[0]
Expand Down
19 changes: 13 additions & 6 deletions pkg/catalogdiagrams/diagrams.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ func TypeFromRef(mod *sysl.Module, appName string, t *TypeData) (string, string,
return "", "", nil // It's most likely a primitive type
}
if ref.Appname != nil {
appName = strings.Join(ref.Appname.Part, "")
appName = strings.Join(ref.Appname.Part, " :: ")
}
if len(ref.Path) > 1 {
appName = ref.Path[0]
Expand All @@ -247,19 +247,26 @@ func TypeFromRef(mod *sysl.Module, appName string, t *TypeData) (string, string,
}
return TypeFromRef(mod, appName, &TypeData{t.alias, ty})
case *sysl.Type_TypeRef:
typeAppName := ""
ref := t.t.GetTypeRef().GetRef()
if ref.Appname != nil {
appName = strings.Join(ref.Appname.Part, "")
typeAppName = strings.Join(ref.GetAppname().GetPart(), " :: ")
} else {
typeAppName = strings.Join(t.t.GetTypeRef().GetContext().GetAppname().GetPart(), " :: ")
}
typeName = strings.Join(ref.Path, ".")
typeName = strings.Join(ref.GetPath(), ".")
if len(ref.Path) > 1 {
appName = ref.Path[0]
typeAppName = ref.Path[0]
typeName = ref.Path[1]
}
if appName == "" {
if typeAppName == "" {
return "", "", nil
}
return appName, typeName, &TypeData{t.alias, mod.Apps[appName].Types[typeName]}
if app, ok := mod.Apps[typeAppName]; ok {
return typeAppName, typeName, &TypeData{t.alias, app.Types[typeName]}
} else {
panic(fmt.Sprintf("no app named %s", typeAppName))
}
}

return "", "", nil
Expand Down
10 changes: 10 additions & 0 deletions tests/namespaced_seq_type.sysl
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
First :: App:
!type VeryComplex:
simpler <: sequence of complex

!type complex:
simple <: string

Second :: App2:
!type KindaComplex:
lessComplex <: sequence of First :: App.VeryComplex

0 comments on commit 318f79e

Please sign in to comment.