-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
40 changed files
with
2,350 additions
and
0 deletions.
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 |
---|---|---|
@@ -0,0 +1,4 @@ | ||
.DS_Store | ||
.cache | ||
.idea | ||
.temp |
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,123 @@ | ||
# Flamalyzer - Static code analysis for Flamingo projects | ||
|
||
Flamalyzer is a vet-like tool which detects common errors in Flamingo projects. | ||
|
||
## Installation | ||
|
||
```shell | ||
go install flamingo.me/flamalyzer@latest | ||
``` | ||
|
||
## Usage | ||
|
||
```shell | ||
Flamalyzer [FLAGS] [PATH] | ||
``` | ||
|
||
### Flags | ||
There are different Flags which can be passed, if no Flags given the Flamalyzer will run in default mode. | ||
|
||
```shell | ||
--configFolder=[PATH] | ||
``` | ||
To define the path to your config-files, the default is `./.flamalyzer` | ||
|
||
```shell | ||
--configSuffix=[SUFFIX] | ||
``` | ||
|
||
To define a string which must occur in the config-files name which should be loaded | ||
(useful if you have different files for different use-cases) | ||
|
||
```shell | ||
--debugFlamalyzer | ||
``` | ||
|
||
To enable more information about what's going on in the program. Like info if the given configFolder-Path isn't configured properly. | ||
|
||
### Run Flamalyzer within vet | ||
|
||
```shell | ||
go vet -vettool=$(which flamalyzer) [PATH] | ||
``` | ||
|
||
### Filewatcher | ||
Flamalyzer can be used as external filewatcher to enable error-highlighting in the IDE. | ||
Flamalyzer's output matches exactly vet's output, so the filewatcher configuration from vet can be used. | ||
|
||
|
||
## Available Analyses | ||
|
||
### Dingo: Pointer receiver check | ||
|
||
This analysis checks that an inject-function has a pointer-receiver | ||
|
||
### Dingo: correct interface binding check | ||
|
||
This analysis checks that an instance implements the interface it is bound to. | ||
|
||
### Dingo: proper inject tags check | ||
|
||
This analysis checks if the inject tags are used properly. | ||
|
||
"inject tags" should be used for annotated injections only (e.g. config), otherwise inject method should be used. | ||
|
||
This means: | ||
|
||
- No empty inject tags | ||
- Inject tags can be defined in the Inject-Function or must be referenced if defined outside | ||
- They must be declared in the same package as the Inject-Function | ||
|
||
#### Architecture: dependency conventions check | ||
|
||
This analysis checks all import statements below the entry path that the provided Group-Conventions are respected. | ||
|
||
Configuration example: | ||
|
||
```yaml | ||
groups: | ||
entrypaths: [ "src/architecture" ] | ||
infrastructure: | ||
allowedDependencies: [ "infrastructure", "interfaces", "application", "domain" ] | ||
interfaces: | ||
allowedDependencies: [ "interfaces", "application", "domain" ] | ||
application: | ||
allowedDependencies: [ "application", "domain" ] | ||
domain: | ||
allowedDependencies: [ "domain" ] | ||
``` | ||
## Configuration | ||
The Configuration is done via **yaml**-files. | ||
The files are expected in `./.flamalyzer` | ||
|
||
The directory can be specified by `--configFolder=[PATH]` | ||
|
||
**config.yaml** example: | ||
```yaml | ||
# Config of the Dingo-ReceiverAnalyzer | ||
dingoAnalyzer: | ||
checkPointerReceiver: false | ||
strictTagsAndFunctions: false | ||
correctInterfaceToInstanceBinding: false | ||
# Config of the dependencyConventions-ReceiverAnalyzer | ||
dependencyConventionsAnalyzer: | ||
entryPaths: [] | ||
dependencyConventions: true | ||
groups: | ||
infrastructure: | ||
allowedDependencies: ["infrastructure", "interfaces", "application", "domain"] | ||
interfaces: | ||
allowedDependencies: ["interfaces", "application", "domain"] | ||
application: | ||
allowedDependencies: ["application", "domain"] | ||
domain: | ||
allowedDependencies: ["domain"] | ||
``` | ||
|
||
There is the possibility to **filter** the files which should be read in. | ||
|
||
Use `--configSuffix=[SUFFIX]` to pass a string which must be part of config-file name. |
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,18 @@ | ||
# this is an example config | ||
debug: false | ||
|
||
# Config of the Dingo-Analyzer | ||
dingoAnalyzer: | ||
checkPointerReceiver: false | ||
checkStrictTagsAndFunctions: false | ||
checkCorrectInterfaceToInstanceBinding: false | ||
|
||
# Config of the DependencyConventions-Analyzer | ||
architectureAnalyzer: | ||
entryPaths: [] | ||
checkDependencyConventions: true | ||
groups: | ||
infrastructure: ["infrastructure", "interfaces", "application", "domain"] | ||
interfaces: ["interfaces", "application", "domain"] | ||
application: ["application", "domain"] | ||
domain: ["domain"] |
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 @@ | ||
# this is an example config | ||
|
||
debug: false | ||
|
||
architectureAnalyzer: | ||
entryPaths: [] | ||
checkDependencyConventions: false | ||
|
||
dingoAnalyzer: | ||
checkPointerReceiver: true | ||
checkStrictTagsAndFunctions: true | ||
checkCorrectInterfaceToInstanceBinding: true |
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,13 @@ | ||
module flamingo.me/flamalyzer | ||
|
||
go 1.16 | ||
|
||
require ( | ||
flamingo.me/dingo v0.2.9 | ||
github.com/mitchellh/mapstructure v1.4.1 | ||
github.com/spf13/pflag v1.0.5 | ||
golang.org/x/mod v0.4.2 // indirect | ||
golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988 // indirect | ||
golang.org/x/tools v0.1.0 | ||
gopkg.in/yaml.v2 v2.4.0 | ||
) |
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 @@ | ||
flamingo.me/dingo v0.2.9 h1:HL7YV4iv3F6xLcUPvIBEzdkbhBSb6PukkZdoOZ8H+Eo= | ||
flamingo.me/dingo v0.2.9/go.mod h1:NXspAYkbktnP0EKs/27QW6Evija8WZfWGtrMcauOejQ= | ||
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/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= | ||
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= | ||
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/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/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= | ||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= | ||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | ||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | ||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | ||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | ||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= | ||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= | ||
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= | ||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= | ||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | ||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= | ||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988 h1:EjgCl+fVlIaPJSori0ikSz3uV0DOHKWOJFpv1sAAhBM= | ||
golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | ||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | ||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | ||
golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= | ||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= | ||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= | ||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||
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.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | ||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= | ||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= |
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,17 @@ | ||
package main | ||
|
||
import ( | ||
"flamingo.me/dingo" | ||
"flamingo.me/flamalyzer/src/analyzers/architecture" | ||
dingoAnalyzer "flamingo.me/flamalyzer/src/analyzers/dingo" | ||
"flamingo.me/flamalyzer/src/flamalyzer" | ||
) | ||
|
||
func main() { | ||
flamalyzer.Run( | ||
[]dingo.Module{ | ||
new(dingoAnalyzer.Module), | ||
new(architecture.Module), | ||
}, | ||
) | ||
} |
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 @@ | ||
package analyzers | ||
|
||
import ( | ||
"reflect" | ||
|
||
"flamingo.me/flamalyzer/src/flamalyzer/configuration" | ||
"github.com/mitchellh/mapstructure" | ||
"golang.org/x/tools/go/analysis" | ||
) | ||
|
||
// AnalyzerProvider returns all bound instances | ||
type AnalyzerProvider func() []Analyzer | ||
|
||
// Analyzer is a collection of checks performed by Flamalyzer. | ||
type Analyzer interface { | ||
ChecksToExecute() []*analysis.Analyzer | ||
} | ||
|
||
// DecodeAnalyzerConfigurationsToAnalyzerProps decodes the props loaded from the config-files to the specific props of an analyzer | ||
// The props musst be passed a Pointer e.g &props | ||
func DecodeAnalyzerConfigurationsToAnalyzerProps(entryName string, config configuration.AnalyzerConfig, propsPtr interface{}) { | ||
if reflect.ValueOf(propsPtr).Type().Kind() != reflect.Ptr { | ||
panic("The passed propsPtr must be a pointer, otherwise the result of this function won't be available in the analyzer!") | ||
} | ||
inputProps := config.GetProps(entryName) | ||
err := mapstructure.Decode(inputProps, &propsPtr) | ||
if err != nil { | ||
panic(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,63 @@ | ||
// Package architecture provides checks targeting architecture conventions | ||
package architecture | ||
|
||
import ( | ||
"flamingo.me/dingo" | ||
"flamingo.me/flamalyzer/src/analyzers" | ||
"flamingo.me/flamalyzer/src/analyzers/architecture/checks/dependency" | ||
"flamingo.me/flamalyzer/src/flamalyzer/configuration" | ||
"golang.org/x/tools/go/analysis" | ||
) | ||
|
||
// Module to register the architecture checks | ||
type Module struct{} | ||
|
||
// The default properties which are used if there is no config-file | ||
var defaultProps = Props{ | ||
EntryPaths: []string{}, | ||
CheckDependencyConventions: true, | ||
Groups: map[string][]string{ | ||
"infrastructure": {"infrastructure", "interfaces", "application", "domain"}, | ||
"interfaces": {"interfaces", "application", "domain"}, | ||
"application": {"application", "domain"}, | ||
"domain": {"domain"}, | ||
}, | ||
} | ||
|
||
// Props of an analyzer which will be used by the config-module to match the entries | ||
// of a file to this variables. Is used to activate and deactivate checks, for example. | ||
type Props struct { | ||
Name string | ||
EntryPaths []string | ||
CheckDependencyConventions bool | ||
Groups map[string][]string | ||
} | ||
|
||
// The Analyzer holds a set of checks, uses the config and has props that can be defined to get read by the config | ||
type Analyzer struct { | ||
checks []*analysis.Analyzer | ||
config configuration.AnalyzerConfig | ||
props Props | ||
} | ||
|
||
// Configure DI | ||
func (m *Module) Configure(injector *dingo.Injector) { | ||
injector.BindMulti(new(analyzers.Analyzer)).To(new(Analyzer)) | ||
} | ||
|
||
// Inject dependencies | ||
func (d *Analyzer) Inject(config configuration.AnalyzerConfig) { | ||
d.props = defaultProps | ||
d.props.Name = "architectureAnalyzer" | ||
d.config = config | ||
} | ||
|
||
// ChecksToExecute decides which checks to run | ||
func (d *Analyzer) ChecksToExecute() []*analysis.Analyzer { | ||
analyzers.DecodeAnalyzerConfigurationsToAnalyzerProps(d.props.Name, d.config, &d.props) | ||
|
||
if d.props.CheckDependencyConventions { | ||
d.checks = append(d.checks, dependency.NewAnalyzer(d.props.Groups, d.props.EntryPaths).Analyzer) | ||
} | ||
return d.checks | ||
} |
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,20 @@ | ||
// This module configures the Testing with the "analysistest" package | ||
package architecture | ||
|
||
import ( | ||
"path/filepath" | ||
"testing" | ||
|
||
"flamingo.me/flamalyzer/src/analyzers/architecture/checks/dependency" | ||
"golang.org/x/tools/go/analysis/analysistest" | ||
) | ||
|
||
func TestArchitectureConventions(t *testing.T) { | ||
analysis := dependency.NewAnalyzer(map[string][]string{ | ||
"infrastructure": {"infrastructure", "interfaces", "application", "domain"}, | ||
"interfaces": {"interfaces", "application", "domain"}, | ||
"application": {"application", "domain"}, | ||
"domain": {"domain"}, | ||
}, []string{}) | ||
analysistest.Run(t, filepath.Join(analysistest.TestData(), "/dependencyConventions"), analysis.Analyzer, "./...") | ||
} |
Oops, something went wrong.