Repository: datreeio/datree
Pull request #411 (2022-02-08 13:59:00)

feat: implement simple output for CI env


Patch:
diff --git a/bl/evaluation/evaluator.go b/bl/evaluation/evaluator.go
index a82c701..b02912e 100644
--- a/bl/evaluation/evaluator.go
+++ b/bl/evaluation/evaluator.go
@@ -2,6 +2,7 @@ package evaluation
 
 import (
 	"github.com/datreeio/datree/bl/validation"
+	"github.com/datreeio/datree/pkg/ciContext"
 	"github.com/datreeio/datree/pkg/cliClient"
 	"github.com/datreeio/datree/pkg/extractor"
 )
@@ -40,7 +41,7 @@ type EvaluationResults struct {
 	}
 }
 
-func (e *Evaluator) CreateEvaluation(cliId string, cliVersion string, k8sVersion string, policyName string) (*cliClient.CreateEvaluationResponse, error) {
+func (e *Evaluator) CreateEvaluation(cliId string, cliVersion string, k8sVersion string, policyName string, ciContext *ciContext.CIContext) (*cliClient.CreateEvaluationResponse, error) {
 	createEvaluationResponse, err := e.cliClient.CreateEvaluation(&cliClient.CreateEvaluationRequest{
 		K8sVersion: &k8sVersion,
 		CliId:      cliId,
@@ -50,6 +51,7 @@ func (e *Evaluator) CreateEvaluation(cliId string, cliVersion string, k8sVersion
 			Os:              e.osInfo.OS,
 			PlatformVersion: e.osInfo.PlatformVersion,
 			KernelVersion:   e.osInfo.KernelVersion,
+			CIContext:       ciContext,
 		},
 	})
 
diff --git a/pkg/ciContext/ciContext.go b/pkg/ciContext/ciContext.go
new file mode 100644
index 0000000..f6f8d59
--- /dev/null
+++ b/pkg/ciContext/ciContext.go
@@ -0,0 +1,79 @@
+package ciContext
+
+import (
+	"fmt"
+	"os"
+	"strings"
+)
+
+type CIContext struct {
+	IsCI  bool   `json:"isCI"`
+	CIEnv string `json:"ciEnv"`
+}
+
+var ciMap = map[string]string{
+	"GITHUB_ACTIONS":                     "github_actions",
+	"GITLAB_CI":                          "gitlab_ci",
+	"CIRCLECI":                           "circle-ci",
+	"JENKINS_HOME":                       "jenkins",
+	"JENKINS_URL":                        "jenkins",
+	"BUILDKITE":                          "buildkite",
+	"SYSTEM_COLLECTIONURI":               fmt.Sprintf("azure_devops_%s", os.Getenv("BUILD_REPOSITORY_PROVIDER")),
+	"SYSTEM_TEAMFOUNDATIONCOLLECTIONURI": "azure-pipelines",
+	"TFC_RUN_ID":                         "tfc",
+	"ENV0_ENVIRONMENT_ID":                "env0",
+	"CF_BUILD_ID":                        "codefresh",
+	"TRAVIS":                             "travis",
+	"CODEBUILD_CI":                       "codebuild",
+	"TEAMCITY_VERSION":                   "teamcity",
+	"BUDDYBUILD_BRANCH":                  "buddybuild",
+	"BUDDY_WORKSPACE_ID":                 "buddy",
+	"APPVEYOR":                           "appveyor",
+	"WERCKER_GIT_BRANCH":                 "wercker",
+	"WERCKER":                            "wercker",
+	"SHIPPABLE":                          "shippable",
+	"BITBUCKET_BUILD_NUMBER":             "bitbucket-pipelines",
+	"CIRRUS_CI":                          "cirrusci",
+	"DRONE":                              "drone",
+	"GO_PIPELINE_NAME":                   "gocd",
+	"SAIL_CI":                            "sail",
+}
+
+var ciMapPrefix = map[string]string{
+	"ATLANTIS_":  "atlantis",
+	"BITBUCKET_": "bitbucket",
+	"CONCOURSE_": "concourse",
+	"SPACELIFT_": "spacelift",
+	"HARNESS_":   "harness",
+}
+
+func Extract() *CIContext {
+	var checkCIEnv = isCI()
+	return &CIContext{
+		IsCI:  checkCIEnv != "none",
+		CIEnv: checkCIEnv,
+	}
+}
+
+func isCI() string {
+	for env, name := range ciMap {
+		if isKeyInEnv(env) {
+			return name
+		}
+	}
+
+	for _, key := range os.Environ() {
+		for prefix, name := range ciMapPrefix {
+			if strings.HasPrefix(key, prefix) {
+				return name
+			}
+		}
+	}
+
+	return "none"
+}
+
+func isKeyInEnv(key string) bool {
+	_, present := os.LookupEnv(key)
+	return present
+}
diff --git a/pkg/cliClient/evaluation.go b/pkg/cliClient/evaluation.go
index 8640f1c..bb615aa 100644
--- a/pkg/cliClient/evaluation.go
+++ b/pkg/cliClient/evaluation.go
@@ -4,14 +4,16 @@ import (
 	"encoding/json"
 	"net/http"
 
+	"github.com/datreeio/datree/pkg/ciContext"
 	"github.com/datreeio/datree/pkg/extractor"
 )
 
 type Metadata struct {
-	CliVersion      string `json:"cliVersion"`
-	Os              string `json:"os"`
-	PlatformVersion string `json:"platformVersion"`
-	KernelVersion   string `json:"kernelVersion"`
+	CliVersion      string               `json:"cliVersion"`
+	Os              string               `json:"os"`
+	PlatformVersion string               `json:"platformVersion"`
+	KernelVersion   string               `json:"kernelVersion"`
+	CIContext       *ciContext.CIContext `json:"ciContext"`
 }
 
 type CreateEvaluationRequest struct {


Test patch:
diff --git a/bl/evaluation/evaluator_test.go b/bl/evaluation/evaluator_test.go
index 89a1fb1..a725e7b 100644
--- a/bl/evaluation/evaluator_test.go
+++ b/bl/evaluation/evaluator_test.go
@@ -4,6 +4,7 @@ import (
 	"path/filepath"
 	"testing"
 
+	"github.com/datreeio/datree/pkg/ciContext"
 	"github.com/datreeio/datree/pkg/cliClient"
 	"github.com/datreeio/datree/pkg/extractor"
 	"github.com/stretchr/testify/assert"
@@ -78,13 +79,27 @@ func TestCreateEvaluation(t *testing.T) {
 		cliVersion := "0.0.7"
 		k8sVersion := "1.18.1"
 		policyName := "Default"
+		ciContext := &ciContext.CIContext{
+			IsCI:  true,
+			CIEnv: "travis",
+		}
 
 		mockedCliClient.On("CreateEvaluation", mock.Anything).Return(&cliClient.CreateEvaluationResponse{EvaluationId: 1, K8sVersion: k8sVersion}, nil)
 
 		expectedCreateEvaluationResponse := &cliClient.CreateEvaluationResponse{EvaluationId: 1, K8sVersion: k8sVersion}
-		createEvaluationResponse, _ := evaluator.CreateEvaluation(cliId, cliVersion, k8sVersion, policyName)
-
-		mockedCliClient.AssertCalled(t, "CreateEvaluation", mock.Anything)
+		createEvaluationResponse, _ := evaluator.CreateEvaluation(cliId, cliVersion, k8sVersion, policyName, ciContext)
+		mockedCliClient.AssertCalled(t, "CreateEvaluation", &cliClient.CreateEvaluationRequest{
+			K8sVersion: &k8sVersion,
+			CliId:      cliId,
+			PolicyName: policyName,
+			Metadata: &cliClient.Metadata{
+				CliVersion:      cliVersion,
+				Os:              evaluator.osInfo.OS,
+				PlatformVersion: evaluator.osInfo.PlatformVersion,
+				KernelVersion:   evaluator.osInfo.KernelVersion,
+				CIContext:       ciContext,
+			},
+		})
 		assert.Equal(t, expectedCreateEvaluationResponse, createEvaluationResponse)
 
 	})
diff --git a/cmd/test/main.go b/cmd/test/main.go
index 9521efd..0529997 100644
--- a/cmd/test/main.go
+++ b/cmd/test/main.go
@@ -11,7 +11,9 @@ import (
 	"github.com/datreeio/datree/bl/files"
 	"github.com/datreeio/datree/bl/messager"
 	"github.com/datreeio/datree/bl/validation"
+	"github.com/datreeio/datree/pkg/ciContext"
 	"github.com/datreeio/datree/pkg/cliClient"
+
 	"github.com/datreeio/datree/pkg/extractor"
 	"github.com/datreeio/datree/pkg/localConfig"
 	"github.com/datreeio/datree/pkg/printer"
@@ -24,7 +26,7 @@ import (
 
 type Evaluator interface {
 	Evaluate(filesConfigurations []*extractor.FileConfigurations, evaluationResponse *cliClient.CreateEvaluationResponse, isInteractiveMode bool) (evaluation.ResultType, error)
-	CreateEvaluation(cliId string, cliVersion string, k8sVersion string, policyName string) (*cliClient.CreateEvaluationResponse, error)
+	CreateEvaluation(cliId string, cliVersion string, k8sVersion string, policyName string, ciContext *ciContext.CIContext) (*cliClient.CreateEvaluationResponse, error)
 	UpdateFailedYamlValidation(invalidFiles []*validation.InvalidYamlFile, evaluationId int, stopEvaluation bool) error
 	UpdateFailedK8sValidation(invalidFiles []*validation.InvalidK8sFile, evaluationId int, stopEvaluation bool) error
 }
@@ -48,6 +50,8 @@ type TestCommandFlags struct {
 	SchemaLocations      []string
 }
 
+//
+
 func (flags *TestCommandFlags) Validate() error {
 	outputValue := flags.Output
 
@@ -173,7 +177,11 @@ func New(ctx *TestCommandContext) *cobra.Command {
 		},
 	}
 
-	testCommand.Flags().StringP("output", "o", "", "Define output format")
+	if ciContext.Extract().IsCI {
+		testCommand.Flags().StringP("output", "o", "simple", "Define output format")
+	} else {
+		testCommand.Flags().StringP("output", "o", "", "Define output format")
+	}
 	testCommand.Flags().StringP("schema-version", "s", "", "Set kubernetes version to validate against. Defaults to 1.18.0")
 	testCommand.Flags().StringP("policy", "p", "", "Policy name to run against")
 	testCommand.Flags().Bool("only-k8s-files", false, "Evaluate only valid yaml files with the properties 'apiVersion' and 'kind'. Ignore everything else")
@@ -313,7 +321,9 @@ func evaluate(ctx *TestCommandContext, filesPaths []string, flags TestCommandFla
 	validationManager := &ValidationManager{}
 	filesPathsLen := len(filesPaths)
 
-	createEvaluationResponse, err := ctx.Evaluator.CreateEvaluation(cliId, ctx.CliVersion, flags.K8sVersion, flags.PolicyName)
+	ciContext := ciContext.Extract()
+
+	createEvaluationResponse, err := ctx.Evaluator.CreateEvaluation(cliId, ctx.CliVersion, flags.K8sVersion, flags.PolicyName, ciContext)
 	if err != nil {
 		return validationManager, nil, evaluation.ResultType{}, err
 	}
diff --git a/cmd/test/main_test.go b/cmd/test/main_test.go
index 53b010a..a0b0a7d 100644
--- a/cmd/test/main_test.go
+++ b/cmd/test/main_test.go
@@ -4,6 +4,7 @@ import (
 	"testing"
 
 	"github.com/datreeio/datree/bl/validation"
+	"github.com/datreeio/datree/pkg/ciContext"
 	"github.com/datreeio/datree/pkg/cliClient"
 	"github.com/datreeio/datree/pkg/extractor"
 	"github.com/datreeio/datree/pkg/printer"
@@ -24,7 +25,7 @@ func (m *mockEvaluator) Evaluate(filesConfigurationsChan []*extractor.FileConfig
 	return args.Get(0).(evaluation.ResultType), args.Error(1)
 }
 
-func (m *mockEvaluator) CreateEvaluation(cliId string, cliVersion string, k8sVersion string, policyName string) (*cliClient.CreateEvaluationResponse, error) {
+func (m *mockEvaluator) CreateEvaluation(cliId string, cliVersion string, k8sVersion string, policyName string, ciContext *ciContext.CIContext) (*cliClient.CreateEvaluationResponse, error) {
 	args := m.Called(cliId, cliVersion, k8sVersion, policyName)
 	return args.Get(0).(*cliClient.CreateEvaluationResponse), args.Error(1)
 }