Skip to content

Commit

Permalink
Merge branch 'main' into gitlab_provider
Browse files Browse the repository at this point in the history
  • Loading branch information
B3rs authored Jan 24, 2024
2 parents ab5d5a7 + 9fc72df commit 0b9b8a4
Show file tree
Hide file tree
Showing 5 changed files with 251 additions and 10 deletions.
30 changes: 30 additions & 0 deletions config.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ git:
path: /home/mcorbin/.ssh/my_ssh_private_key
password: key-password # you can use GIT_PRIVATE_KEY_PASSWORD







groups:
- name: golang
checks:
Expand Down Expand Up @@ -112,3 +118,27 @@ rules:
pattern: "NewGrepRule"
match: true

- name: allowed-projects
project:
- names:
- awesome-project1
- awesome-project2
match: true
- name: excluded-projects
project:
- names:
- bad-project1
- bad-project2
match: false
- name: matching-all-labels
project:
- labels:
team: backend
language: golang
match: true
- name: excluding-all-labels
project:
- names:
team: backend
language: golang
match: false
28 changes: 18 additions & 10 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,17 @@ import (
type Config struct {
HTTP HTTPConfig `validate:"omitempty"`
Providers ProvidersConfig `validate:"omitempty"`
Groups []Group
Checks []Check
Rules []Rule
Labels []string
Groups []Group `validate:"dive"`
Checks []Check `validate:"dive"`
Rules []Rule `validate:"dive"`
Labels []string `validate:"dive"`
Interval int
Git GitConfig
}

type ProvidersConfig struct {
ArgoCD ArgoCDConfig `validate:"omitempty"`
Static []project.Project `validate:"omitempty"`
Static []project.Project `validate:"omitempty,dive"`
Gitlab GitlabConfig `validate:"omitempty"`
}

Expand All @@ -41,10 +41,11 @@ type GitlabConfig struct {
}

type Rule struct {
Name string `validate:"required"`
Files []FileRule
Grep []GrepRule
Simple *bool
Name string `validate:"required"`
Files []FileRule `validate:"dive"`
Grep []GrepRule `validate:"dive"`
Project []ProjectRule `validate:"dive"`
Simple *bool
}

type FileRule struct {
Expand All @@ -62,10 +63,16 @@ type GrepRule struct {
SkipNotFound bool `yaml:"skip-not-found"`
}

type ProjectRule struct {
Names []string
Labels map[string]string
Match *bool
}

type Check struct {
Name string `validate:"required"`
Labels map[string]string
Operator string `validate:"oneof=and or"`
Operator string `validate:"oneof='and' 'or' ''"`
Rules []string `validate:"required,min=1"`
}

Expand Down Expand Up @@ -95,5 +102,6 @@ func New(path string) (*Config, []byte, error) {
if err != nil {
return nil, nil, err
}

return &config, content, nil
}
4 changes: 4 additions & 0 deletions pkg/ruler/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ func newRule(config config.Rule) *rule {
for _, grepConfig := range config.Grep {
modules = append(modules, rules.NewGrepRule(grepConfig))
}
for _, projectConfig := range config.Project {
modules = append(modules, rules.NewProjectRule(projectConfig))
}

if config.Simple != nil {
value := *config.Simple
modules = append(modules, rules.NewSimpleRule(value))
Expand Down
67 changes: 67 additions & 0 deletions pkg/ruler/rules/project.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package rules

import (
"context"
"fmt"

"github.com/qonto/standards-insights/config"
"github.com/qonto/standards-insights/pkg/project"
)

type ProjectRule struct {
config config.ProjectRule
}

func NewProjectRule(config config.ProjectRule) *ProjectRule {
return &ProjectRule{
config: config,
}
}

func (rule *ProjectRule) Do(ctx context.Context, project project.Project) error {
match := true
if rule.config.Match != nil {
match = *rule.config.Match
}

if len(rule.config.Names) > 0 {
if match && !contains(project.Name, rule.config.Names) {
return fmt.Errorf("project name %s is not in %v", project.Name, rule.config.Names)
}
if !match && contains(project.Name, rule.config.Names) {
return fmt.Errorf("project name %s is matching one of %v", project.Name, rule.config.Names)
}
}

if len(rule.config.Labels) > 0 {
if match && !isSubset(rule.config.Labels, project.Labels) {
return fmt.Errorf("project labels %v does not contain %v", project.Labels, rule.config.Labels)
}
if !match && isSubset(rule.config.Labels, project.Labels) {
return fmt.Errorf("project labels %v contain %v", project.Labels, rule.config.Labels)
}
}

return nil
}

func isSubset(a, b map[string]string) bool {
if len(a) > len(b) {
return false
}
for k, vsub := range a {
if vm, found := b[k]; !found || vm != vsub {
return false
}
}
return true
}

func contains(s string, slice []string) bool {
for _, v := range slice {
if s == v {
return true
}
}
return false
}
132 changes: 132 additions & 0 deletions pkg/ruler/rules/project_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package rules

import (
"context"
"errors"
"testing"

"github.com/qonto/standards-insights/config"
"github.com/qonto/standards-insights/pkg/project"
"github.com/stretchr/testify/assert"
)

func TestProjectRule_Do(t *testing.T) {
f := false
tests := []struct {
name string
config config.ProjectRule
project project.Project
wantErr error
}{
{
name: "empty rule should pass",
config: config.ProjectRule{},
project: project.Project{Name: "a", Labels: map[string]string{"a": "b"}},
wantErr: nil,
},
{
name: "project name list match",
config: config.ProjectRule{
Names: []string{"a", "b", "c"},
},
project: project.Project{Name: "b"},
wantErr: nil,
},
{
name: "project name does not match list",
config: config.ProjectRule{
Names: []string{"a", "b", "c"},
},
project: project.Project{Name: "f"},
wantErr: errors.New("project name f is not in [a b c]"),
},
{
name: "project name matches list and should not",
config: config.ProjectRule{
Names: []string{"a", "b", "c"},
Match: &f,
},
project: project.Project{Name: "a"},
wantErr: errors.New("project name a is matching one of [a b c]"),
},
{
name: "project name does not match list and should not",
config: config.ProjectRule{
Names: []string{"a", "b", "c"},
Match: &f,
},
project: project.Project{Name: "e"},
wantErr: nil,
},

{
name: "project labels full match",
config: config.ProjectRule{
Labels: map[string]string{
"a": "b",
"e": "f",
},
},
project: project.Project{Labels: map[string]string{
"a": "b",
"c": "d",
"e": "f",
}},
wantErr: nil,
},
{
name: "project labels not matching",
config: config.ProjectRule{
Labels: map[string]string{
"a": "b",
"e": "f",
},
},
project: project.Project{Labels: map[string]string{
"a": "b",
"c": "d",
"g": "h",
}},
wantErr: errors.New("project labels map[a:b c:d g:h] does not contain map[a:b e:f]"),
},
{
name: "project labels should not match",
config: config.ProjectRule{
Labels: map[string]string{
"a": "b",
"e": "f",
},
Match: &f,
},
project: project.Project{Labels: map[string]string{
"a": "b",
"c": "d",
"e": "f",
}},
wantErr: errors.New("project labels map[a:b c:d e:f] contain map[a:b e:f]"),
},
{
name: "project labels should not match and don't match",
config: config.ProjectRule{
Labels: map[string]string{
"a": "b",
"e": "h",
},
Match: &f,
},
project: project.Project{Labels: map[string]string{
"a": "b",
"c": "d",
"e": "f",
}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
rule := NewProjectRule(tt.config)

err := rule.Do(context.Background(), tt.project)
assert.Equal(t, tt.wantErr, err)
})
}
}

0 comments on commit 0b9b8a4

Please sign in to comment.