mirror of
https://github.com/SAP/jenkins-library.git
synced 2025-01-20 05:19:40 +02:00
feat(go): add telemetry reporting (#1100)
* Add telemetry support * First round telemetry * Add telemetry flag * fix: move files to avoid import cycles * add noTelemetry as global config option * Respect telemetry configuration for reporting * add site id, swa endpoint * correct logger initialization * add http logic * rename init method * rename consts & types * convert struct to payload * convert data to payload string * move activation flag out of data structure * extract types to own file * build query using net/url * correct field mapping * extract notify coding to own file * cleanup parameter mapping * preare base data * fix codeclimate issue * correct test case * fill values from env * test all fields * untrack notify.go * ignore empty custom values * cleanup data.go * add test cases * cleanup * add usage reporting to karma step * add usage reporting to step generator * externalise siteID * correct custom field names * test env handling * simplify method signature * revert parameter negation * correct import * adjust golden file * inclease log level * ignore test case * Revert "inclease log level" This reverts commit 70cae0e0296afb2aa9e7d71e83ea70aa83d1a6d7. * add test case for envvars * remove duplicate reporting * remove duplicate reporting * correct format * regenerate checkmarx file * add log message on deactivation * rename function * add comments to understand SWA mapping Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>
This commit is contained in:
parent
92441577d8
commit
aa3fb8adb4
@ -12,7 +12,8 @@ RUN export GIT_COMMIT=$(git rev-parse HEAD) && \
|
||||
CGO_ENABLED=0 go build \
|
||||
-ldflags \
|
||||
"-X github.com/SAP/jenkins-library/cmd.GitCommit=${GIT_COMMIT} \
|
||||
-X github.com/SAP/jenkins-library/pkg/log.LibraryRepository=${GIT_REPOSITORY}" \
|
||||
-X github.com/SAP/jenkins-library/pkg/log.LibraryRepository=${GIT_REPOSITORY} \
|
||||
-X github.com/SAP/jenkins-library/pkg/telemetry.LibraryRepository=${GIT_REPOSITORY}" \
|
||||
-o piper
|
||||
|
||||
# FROM gcr.io/distroless/base:latest
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"github.com/SAP/jenkins-library/pkg/config"
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
"github.com/SAP/jenkins-library/pkg/piperenv"
|
||||
"github.com/SAP/jenkins-library/pkg/telemetry"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@ -33,7 +34,6 @@ type checkmarxExecuteScanOptions struct {
|
||||
VulnerabilityThresholdMedium int `json:"vulnerabilityThresholdMedium,omitempty"`
|
||||
VulnerabilityThresholdResult string `json:"vulnerabilityThresholdResult,omitempty"`
|
||||
VulnerabilityThresholdUnit string `json:"vulnerabilityThresholdUnit,omitempty"`
|
||||
Verbose bool `json:"verbose,omitempty"`
|
||||
}
|
||||
|
||||
type checkmarxExecuteScanInflux struct {
|
||||
@ -186,6 +186,8 @@ thresholds instead of ` + "`" + `percentage` + "`" + ` whereas we strongly recom
|
||||
}
|
||||
log.DeferExitHandler(handler)
|
||||
defer handler()
|
||||
telemetry.Initialize(GeneralConfig.NoTelemetry, "checkmarxExecuteScan")
|
||||
telemetry.Send(&telemetry.CustomData{})
|
||||
return checkmarxExecuteScan(myCheckmarxExecuteScanOptions, &influx)
|
||||
},
|
||||
}
|
||||
@ -216,7 +218,6 @@ func addCheckmarxExecuteScanFlags(cmd *cobra.Command) {
|
||||
cmd.Flags().IntVar(&myCheckmarxExecuteScanOptions.VulnerabilityThresholdMedium, "vulnerabilityThresholdMedium", 100, "The specific threshold for medium severity findings")
|
||||
cmd.Flags().StringVar(&myCheckmarxExecuteScanOptions.VulnerabilityThresholdResult, "vulnerabilityThresholdResult", "FAILURE", "The result of the build in case thresholds are enabled and exceeded")
|
||||
cmd.Flags().StringVar(&myCheckmarxExecuteScanOptions.VulnerabilityThresholdUnit, "vulnerabilityThresholdUnit", "percentage", "The unit for the threshold to apply.")
|
||||
cmd.Flags().BoolVar(&myCheckmarxExecuteScanOptions.Verbose, "verbose", false, "Whether the step shall provide verbose logging output")
|
||||
|
||||
cmd.MarkFlagRequired("password")
|
||||
cmd.MarkFlagRequired("projectName")
|
||||
@ -398,14 +399,6 @@ func checkmarxExecuteScanMetadata() config.StepData {
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{},
|
||||
},
|
||||
{
|
||||
Name: "verbose",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"},
|
||||
Type: "bool",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/SAP/jenkins-library/pkg/config"
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
"github.com/SAP/jenkins-library/pkg/telemetry"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@ -37,6 +38,8 @@ func DetectExecuteScanCommand() *cobra.Command {
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
|
||||
telemetry.Initialize(GeneralConfig.NoTelemetry, "detectExecuteScan")
|
||||
telemetry.Send(&telemetry.CustomData{})
|
||||
return detectExecuteScan(myDetectExecuteScanOptions)
|
||||
},
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/SAP/jenkins-library/pkg/config"
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
"github.com/SAP/jenkins-library/pkg/telemetry"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@ -42,6 +43,8 @@ It can for example be used for GitOps scenarios or for scenarios where you want
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
|
||||
telemetry.Initialize(GeneralConfig.NoTelemetry, "githubCreatePullRequest")
|
||||
telemetry.Send(&telemetry.CustomData{})
|
||||
return githubCreatePullRequest(myGithubCreatePullRequestOptions)
|
||||
},
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/SAP/jenkins-library/pkg/config"
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
"github.com/SAP/jenkins-library/pkg/telemetry"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@ -52,6 +53,8 @@ The result looks like
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
|
||||
telemetry.Initialize(GeneralConfig.NoTelemetry, "githubPublishRelease")
|
||||
telemetry.Send(&telemetry.CustomData{})
|
||||
return githubPublishRelease(myGithubPublishReleaseOptions)
|
||||
},
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package cmd
|
||||
import (
|
||||
"github.com/SAP/jenkins-library/pkg/config"
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
"github.com/SAP/jenkins-library/pkg/telemetry"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@ -40,6 +41,8 @@ In the Docker network, the containers can be referenced by the values provided i
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
|
||||
telemetry.Initialize(GeneralConfig.NoTelemetry, "karmaExecuteTests")
|
||||
telemetry.Send(&telemetry.CustomData{})
|
||||
return karmaExecuteTests(myKarmaExecuteTestsOptions)
|
||||
},
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/SAP/jenkins-library/pkg/config"
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
"github.com/SAP/jenkins-library/pkg/telemetry"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@ -65,6 +66,8 @@ helm upgrade <deploymentName> <chartPath> --install --force --namespace <namespa
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
|
||||
telemetry.Initialize(GeneralConfig.NoTelemetry, "kubernetesDeploy")
|
||||
telemetry.Send(&telemetry.CustomData{})
|
||||
return kubernetesDeploy(myKubernetesDeployOptions)
|
||||
},
|
||||
}
|
||||
|
12
cmd/piper.go
12
cmd/piper.go
@ -19,6 +19,7 @@ type GeneralConfigOptions struct {
|
||||
DefaultConfig []string //ordered list of Piper default configurations. Can be filePath or ENV containing JSON in format 'ENV:MY_ENV_VAR'
|
||||
ParametersJSON string
|
||||
EnvRootPath string
|
||||
NoTelemetry bool
|
||||
StageName string
|
||||
StepConfigJSON string
|
||||
StepMetadata string //metadata to be considered, can be filePath or ENV containing JSON in format 'ENV:MY_ENV_VAR'
|
||||
@ -67,6 +68,7 @@ func addRootFlags(rootCmd *cobra.Command) {
|
||||
rootCmd.PersistentFlags().StringVar(&GeneralConfig.EnvRootPath, "envRootPath", ".pipeline", "Root path to Piper pipeline shared environments")
|
||||
rootCmd.PersistentFlags().StringVar(&GeneralConfig.StageName, "stageName", os.Getenv("STAGE_NAME"), "Name of the stage for which configuration should be included")
|
||||
rootCmd.PersistentFlags().StringVar(&GeneralConfig.StepConfigJSON, "stepConfigJSON", os.Getenv("PIPER_stepConfigJSON"), "Step configuration in JSON format")
|
||||
rootCmd.PersistentFlags().BoolVar(&GeneralConfig.NoTelemetry, "noTelemetry", false, "Disables telemetry reporting")
|
||||
rootCmd.PersistentFlags().BoolVarP(&GeneralConfig.Verbose, "verbose", "v", false, "verbose output")
|
||||
|
||||
}
|
||||
@ -75,6 +77,12 @@ func addRootFlags(rootCmd *cobra.Command) {
|
||||
func PrepareConfig(cmd *cobra.Command, metadata *config.StepData, stepName string, options interface{}, openFile func(s string) (io.ReadCloser, error)) error {
|
||||
|
||||
filters := metadata.GetParameterFilters()
|
||||
|
||||
// add telemetry parameter "collectTelemetryData" to ALL, GENERAL and PARAMETER filters
|
||||
filters.All = append(filters.All, "collectTelemetryData")
|
||||
filters.General = append(filters.General, "collectTelemetryData")
|
||||
filters.Parameters = append(filters.Parameters, "collectTelemetryData")
|
||||
|
||||
resourceParams := metadata.GetResourceParameters(GeneralConfig.EnvRootPath, "commonPipelineEnvironment")
|
||||
|
||||
flagValues := config.AvailableFlagValues(cmd, &filters)
|
||||
@ -119,6 +127,10 @@ func PrepareConfig(cmd *cobra.Command, metadata *config.StepData, stepName strin
|
||||
}
|
||||
}
|
||||
|
||||
if fmt.Sprintf("%v", stepConfig.Config["collectTelemetryData"]) == "false" {
|
||||
GeneralConfig.NoTelemetry = true
|
||||
}
|
||||
|
||||
if !GeneralConfig.Verbose {
|
||||
if stepConfig.Config["verbose"] != nil && stepConfig.Config["verbose"].(bool) {
|
||||
log.SetVerbose(stepConfig.Config["verbose"].(bool))
|
||||
|
@ -3,6 +3,7 @@ package cmd
|
||||
import (
|
||||
"github.com/SAP/jenkins-library/pkg/config"
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
"github.com/SAP/jenkins-library/pkg/telemetry"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@ -27,6 +28,8 @@ func VersionCommand() *cobra.Command {
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
|
||||
telemetry.Initialize(GeneralConfig.NoTelemetry, "version")
|
||||
telemetry.Send(&telemetry.CustomData{})
|
||||
return version(myVersionOptions)
|
||||
},
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/SAP/jenkins-library/pkg/config"
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
"github.com/SAP/jenkins-library/pkg/telemetry"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@ -42,6 +43,8 @@ func XsDeployCommand() *cobra.Command {
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
|
||||
telemetry.Initialize(GeneralConfig.NoTelemetry, "xsDeploy")
|
||||
telemetry.Send(&telemetry.CustomData{})
|
||||
return xsDeploy(myXsDeployOptions)
|
||||
},
|
||||
}
|
||||
|
8
go.mod
8
go.mod
@ -13,9 +13,11 @@ require (
|
||||
github.com/spf13/cobra v0.0.5
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.4.0
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 // indirect
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 // indirect
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 // indirect
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
|
||||
gopkg.in/yaml.v2 v2.2.4 // indirect
|
||||
)
|
||||
|
18
go.sum
18
go.sum
@ -31,7 +31,9 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
@ -62,15 +64,15 @@ github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 h1:iMGN4xG0cnqj3t+zOM8wUB0BiPKHEwSxEZCvzcbZuvk=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@ -83,12 +85,16 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e h1:D5TXcfTk7xF7hvieo4QErS3qqCB4teTffacDWr7CI+0=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
@ -39,6 +39,7 @@ import (
|
||||
{{ if .ExportPrefix}}{{ .ExportPrefix }} "github.com/SAP/jenkins-library/cmd"{{ end -}}
|
||||
"github.com/SAP/jenkins-library/pkg/config"
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
"github.com/SAP/jenkins-library/pkg/telemetry"
|
||||
{{ if .OutputResources }}"github.com/SAP/jenkins-library/pkg/piperenv"{{ end }}
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@ -78,6 +79,8 @@ func {{.CobraCmdFuncName}}() *cobra.Command {
|
||||
log.DeferExitHandler(handler)
|
||||
defer handler()
|
||||
{{- end }}
|
||||
telemetry.Initialize(GeneralConfig.NoTelemetry, "{{ .StepName }}")
|
||||
telemetry.Send(&telemetry.CustomData{})
|
||||
return {{.StepName}}(my{{ .StepName | title }}Options{{ range $notused, $oRes := .OutputResources}}, &{{ index $oRes "name" }}{{ end }})
|
||||
},
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/SAP/jenkins-library/pkg/config"
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
"github.com/SAP/jenkins-library/pkg/telemetry"
|
||||
"github.com/SAP/jenkins-library/pkg/piperenv"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@ -110,6 +111,8 @@ func TestStepCommand() *cobra.Command {
|
||||
}
|
||||
log.DeferExitHandler(handler)
|
||||
defer handler()
|
||||
telemetry.Initialize(GeneralConfig.NoTelemetry, "testStep")
|
||||
telemetry.Send(&telemetry.CustomData{})
|
||||
return testStep(myTestStepOptions, &commonPipelineEnvironment, &influxTest)
|
||||
},
|
||||
}
|
||||
|
@ -130,6 +130,7 @@ func (c *Client) SetOptions(options ClientOptions) {
|
||||
|
||||
func (c *Client) initialize() *http.Client {
|
||||
c.applyDefaults()
|
||||
c.logger = log.Entry().WithField("package", "SAP/jenkins-library/pkg/http")
|
||||
|
||||
var httpClient = &http.Client{
|
||||
Timeout: c.timeout,
|
||||
|
82
pkg/telemetry/data.go
Normal file
82
pkg/telemetry/data.go
Normal file
@ -0,0 +1,82 @@
|
||||
package telemetry
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// BaseData object definition containing the base data and it's mapping information
|
||||
type BaseData struct {
|
||||
// SWA receives the fields custom1 - custom30 and e_a, e_2 - e_30 for custom values.
|
||||
ActionName string `json:"action_name"`
|
||||
EventType string `json:"event_type"`
|
||||
SiteID string `json:"idsite"`
|
||||
URL string `json:"url"`
|
||||
StepName string `json:"e_3"` // set by step generator
|
||||
StageName string `json:"e_10"`
|
||||
PipelineURLHash string `json:"e_4"` // defaults to sha1 of env.JOB_URl
|
||||
BuildURLHash string `json:"e_5"` // defaults to sha1 of env.BUILD_URL
|
||||
}
|
||||
|
||||
var baseData BaseData
|
||||
|
||||
// BaseMetaData object definition containing the labels for the base data and it's mapping information
|
||||
type BaseMetaData struct {
|
||||
// SWA receives the fields custom1 - custom30 and e_a, e_2 - e_30 for custom values.
|
||||
StepNameLabel string `json:"custom3"`
|
||||
StageNameLabel string `json:"custom10"`
|
||||
PipelineURLHashLabel string `json:"custom4"`
|
||||
BuildURLHashLabel string `json:"custom5"`
|
||||
}
|
||||
|
||||
// baseMetaData object containing the labels for the base data
|
||||
var baseMetaData BaseMetaData = BaseMetaData{
|
||||
StepNameLabel: "stepName",
|
||||
StageNameLabel: "stageName",
|
||||
PipelineURLHashLabel: "pipelineUrlHash",
|
||||
BuildURLHashLabel: "buildUrlHash",
|
||||
}
|
||||
|
||||
// CustomData object definition containing the data that can be set by a step and it's mapping information
|
||||
type CustomData struct {
|
||||
// SWA receives the fields custom1 - custom30 and e_a, e_2 - e_30 for custom values.
|
||||
// Piper uses the values custom11 - custom25 & e_11 - e_25 for library related reporting
|
||||
// and custom26 - custom30 & e_26 - e_30 for step related reporting.
|
||||
Custom1Label string `json:"custom26,omitempty"`
|
||||
Custom2Label string `json:"custom27,omitempty"`
|
||||
Custom3Label string `json:"custom28,omitempty"`
|
||||
Custom4Label string `json:"custom29,omitempty"`
|
||||
Custom5Label string `json:"custom30,omitempty"`
|
||||
Custom1 string `json:"e_26,omitempty"`
|
||||
Custom2 string `json:"e_27,omitempty"`
|
||||
Custom3 string `json:"e_28,omitempty"`
|
||||
Custom4 string `json:"e_29,omitempty"`
|
||||
Custom5 string `json:"e_30,omitempty"`
|
||||
}
|
||||
|
||||
// Data object definition containing all telemetry data
|
||||
type Data struct {
|
||||
BaseData
|
||||
BaseMetaData
|
||||
CustomData
|
||||
}
|
||||
|
||||
// toMap transfers the data object into a map using JSON tags
|
||||
func (d *Data) toMap() (result map[string]string) {
|
||||
jsonObj, _ := json.Marshal(d)
|
||||
json.Unmarshal(jsonObj, &result)
|
||||
return
|
||||
}
|
||||
|
||||
// toPayloadString transfers the data object into a 'key=value&..' string
|
||||
func (d *Data) toPayloadString() string {
|
||||
parameters := url.Values{}
|
||||
|
||||
for key, value := range d.toMap() {
|
||||
if len(value) > 0 {
|
||||
parameters.Add(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
return parameters.Encode()
|
||||
}
|
67
pkg/telemetry/data_test.go
Normal file
67
pkg/telemetry/data_test.go
Normal file
@ -0,0 +1,67 @@
|
||||
package telemetry
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestDataToMap(t *testing.T) {
|
||||
// init
|
||||
testData := Data{BaseData: BaseData{ActionName: "testAction"}, CustomData: CustomData{Custom2Label: "label", Custom2: "value"}}
|
||||
// test
|
||||
result := testData.toMap()
|
||||
// assert
|
||||
assert.Contains(t, result, "action_name")
|
||||
assert.Contains(t, result, "event_type")
|
||||
assert.Contains(t, result, "idsite")
|
||||
assert.Contains(t, result, "url")
|
||||
|
||||
assert.Contains(t, result, "e_3")
|
||||
assert.Contains(t, result, "e_4")
|
||||
assert.Contains(t, result, "e_5")
|
||||
assert.Contains(t, result, "e_10")
|
||||
|
||||
assert.Contains(t, result, "custom3")
|
||||
assert.Contains(t, result, "custom4")
|
||||
assert.Contains(t, result, "custom5")
|
||||
assert.Contains(t, result, "custom10")
|
||||
|
||||
assert.Contains(t, result, "e_27")
|
||||
assert.Contains(t, result, "custom27")
|
||||
|
||||
assert.Equal(t, 14, len(result))
|
||||
}
|
||||
|
||||
func TestDataToPayload(t *testing.T) {
|
||||
t.Run("with single parameter", func(t *testing.T) {
|
||||
// init
|
||||
testData := Data{BaseData: BaseData{ActionName: "testAction"}}
|
||||
// test
|
||||
result := testData.toPayloadString()
|
||||
// assert
|
||||
assert.Contains(t, result, "action_name=testAction")
|
||||
assert.NotContains(t, result, "idsite=")
|
||||
})
|
||||
|
||||
t.Run("with multiple parameters", func(t *testing.T) {
|
||||
// init
|
||||
testData := Data{BaseData: BaseData{ActionName: "testAction", SiteID: "gl8rkd6j211bw3j1fwb8rb4h0000gn"}}
|
||||
// test
|
||||
result := testData.toPayloadString()
|
||||
// assert
|
||||
assert.Contains(t, result, "&")
|
||||
assert.Contains(t, result, "action_name=testAction")
|
||||
assert.Contains(t, result, "idsite=gl8rkd6j211bw3j1fwb8rb4h0000gn")
|
||||
})
|
||||
|
||||
t.Run("encoding", func(t *testing.T) {
|
||||
// init
|
||||
testData := Data{BaseData: BaseData{ActionName: "t€štÄçtïøñ"}}
|
||||
// test
|
||||
result := testData.toPayloadString()
|
||||
// assert
|
||||
assert.Contains(t, result, "t%E2%82%AC%C5%A1t%C3%84%C3%A7t%C3%AF%C3%B8%C3%B1")
|
||||
assert.NotContains(t, result, "t€štÄçtïøñ")
|
||||
})
|
||||
}
|
107
pkg/telemetry/telemetry.go
Normal file
107
pkg/telemetry/telemetry.go
Normal file
@ -0,0 +1,107 @@
|
||||
package telemetry
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
piperhttp "github.com/SAP/jenkins-library/pkg/http"
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
)
|
||||
|
||||
// eventType
|
||||
const eventType = "library-os-ng"
|
||||
|
||||
// actionName
|
||||
const actionName = "Piper Library OS"
|
||||
|
||||
// LibraryRepository that is passed into with -ldflags
|
||||
var LibraryRepository string
|
||||
|
||||
// SiteID ...
|
||||
var SiteID string
|
||||
|
||||
var disabled bool
|
||||
var client piperhttp.Sender
|
||||
|
||||
// Initialize sets up the base telemetry data and is called in generated part of the steps
|
||||
func Initialize(telemetryDisabled bool, stepName string) {
|
||||
disabled = telemetryDisabled
|
||||
|
||||
// skip if telemetry is dieabled
|
||||
if disabled {
|
||||
log.Entry().Info("Telemetry reporting deactivated")
|
||||
return
|
||||
}
|
||||
|
||||
if client == nil {
|
||||
client = &piperhttp.Client{}
|
||||
}
|
||||
|
||||
client.SetOptions(piperhttp.ClientOptions{Timeout: time.Second * 5})
|
||||
|
||||
if len(LibraryRepository) == 0 {
|
||||
LibraryRepository = "https://github.com/n/a"
|
||||
}
|
||||
|
||||
if len(SiteID) == 0 {
|
||||
SiteID = "827e8025-1e21-ae84-c3a3-3f62b70b0130"
|
||||
}
|
||||
|
||||
baseData = BaseData{
|
||||
URL: LibraryRepository,
|
||||
ActionName: actionName,
|
||||
EventType: eventType,
|
||||
StepName: stepName,
|
||||
SiteID: SiteID,
|
||||
PipelineURLHash: getPipelineURLHash(), // http://server:port/jenkins/job/foo/
|
||||
BuildURLHash: getBuildURLHash(), // http://server:port/jenkins/job/foo/15/
|
||||
}
|
||||
//ToDo: register Logrus Hook
|
||||
|
||||
}
|
||||
|
||||
func getPipelineURLHash() string {
|
||||
return toSha1OrNA(os.Getenv("JOB_URL"))
|
||||
}
|
||||
|
||||
func getBuildURLHash() string {
|
||||
return toSha1OrNA(os.Getenv("BUILD_URL"))
|
||||
}
|
||||
|
||||
func toSha1OrNA(input string) string {
|
||||
if len(input) == 0 {
|
||||
return "n/a"
|
||||
}
|
||||
return fmt.Sprintf("%x", sha1.Sum([]byte(input)))
|
||||
}
|
||||
|
||||
// SWA baseURL
|
||||
const baseURL = "https://webanalytics.cfapps.eu10.hana.ondemand.com"
|
||||
|
||||
// SWA endpoint
|
||||
const endpoint = "/tracker/log"
|
||||
|
||||
// Send ...
|
||||
func Send(customData *CustomData) {
|
||||
data := Data{
|
||||
BaseData: baseData,
|
||||
BaseMetaData: baseMetaData,
|
||||
CustomData: *customData,
|
||||
}
|
||||
|
||||
// skip if telemetry is dieabled
|
||||
if disabled {
|
||||
return
|
||||
}
|
||||
|
||||
request, _ := url.Parse(baseURL)
|
||||
request.Path = endpoint
|
||||
request.RawQuery = data.toPayloadString()
|
||||
log.Entry().WithField("request", request.String()).Debug("Sending telemetry data")
|
||||
client.SendRequest(http.MethodGet, request.String(), nil, nil, nil)
|
||||
}
|
111
pkg/telemetry/telemetry_test.go
Normal file
111
pkg/telemetry/telemetry_test.go
Normal file
@ -0,0 +1,111 @@
|
||||
package telemetry
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
piperhttp "github.com/SAP/jenkins-library/pkg/http"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type clientMock struct {
|
||||
httpMethod string
|
||||
urlsCalled string
|
||||
}
|
||||
|
||||
func (c *clientMock) SetOptions(opts piperhttp.ClientOptions) {}
|
||||
|
||||
func (c *clientMock) SendRequest(method, url string, body io.Reader, header http.Header, cookies []*http.Cookie) (*http.Response, error) {
|
||||
c.httpMethod = method
|
||||
c.urlsCalled = url
|
||||
|
||||
return &http.Response{StatusCode: 200, Body: ioutil.NopCloser(bytes.NewReader([]byte("")))}, nil
|
||||
}
|
||||
|
||||
var mock clientMock
|
||||
|
||||
func TestInitialise(t *testing.T) {
|
||||
t.Run("with disabled telemetry", func(t *testing.T) {
|
||||
// init
|
||||
client = nil
|
||||
// test
|
||||
Initialize(true, "testStep")
|
||||
// assert
|
||||
assert.Equal(t, nil, client)
|
||||
assert.Equal(t, BaseData{}, baseData)
|
||||
})
|
||||
|
||||
t.Run("", func(t *testing.T) {
|
||||
// init
|
||||
client = nil
|
||||
// test
|
||||
Initialize(false, "testStep")
|
||||
// assert
|
||||
assert.NotEqual(t, nil, client)
|
||||
assert.Equal(t, "testStep", baseData.StepName)
|
||||
})
|
||||
}
|
||||
func TestSend(t *testing.T) {
|
||||
t.Run("with disabled telemetry", func(t *testing.T) {
|
||||
// init
|
||||
mock = clientMock{}
|
||||
client = &mock
|
||||
disabled = true
|
||||
// test
|
||||
Send(&CustomData{})
|
||||
// assert
|
||||
assert.Equal(t, 0, len(mock.httpMethod))
|
||||
assert.Equal(t, 0, len(mock.urlsCalled))
|
||||
})
|
||||
|
||||
t.Run("", func(t *testing.T) {
|
||||
// init
|
||||
mock = clientMock{}
|
||||
client = &mock
|
||||
disabled = false
|
||||
baseData = BaseData{
|
||||
ActionName: "testAction",
|
||||
}
|
||||
// test
|
||||
Send(&CustomData{
|
||||
Custom1: "test",
|
||||
Custom1Label: "label",
|
||||
})
|
||||
// assert
|
||||
assert.Equal(t, "GET", mock.httpMethod)
|
||||
assert.Contains(t, mock.urlsCalled, baseURL)
|
||||
assert.Contains(t, mock.urlsCalled, "custom26=label")
|
||||
assert.Contains(t, mock.urlsCalled, "e_26=test")
|
||||
assert.Contains(t, mock.urlsCalled, "action_name=testAction")
|
||||
})
|
||||
}
|
||||
func TestEnvVars(t *testing.T) {
|
||||
t.Run("without values", func(t *testing.T) {
|
||||
// init
|
||||
client = nil
|
||||
// test
|
||||
Initialize(false, "testStep")
|
||||
// assert
|
||||
assert.Equal(t, "n/a", baseData.PipelineURLHash)
|
||||
assert.Equal(t, "n/a", baseData.BuildURLHash)
|
||||
})
|
||||
|
||||
t.Run("", func(t *testing.T) {
|
||||
// init
|
||||
os.Setenv("JOB_URL", "someValue")
|
||||
os.Setenv("BUILD_URL", "someValue")
|
||||
client = nil
|
||||
// test
|
||||
Initialize(false, "testStep")
|
||||
// assert
|
||||
assert.Equal(t, "c1353b55ce4db511684b8a3b7b5c4b3d99ee9dec", baseData.PipelineURLHash)
|
||||
assert.Equal(t, "c1353b55ce4db511684b8a3b7b5c4b3d99ee9dec", baseData.BuildURLHash)
|
||||
// cleanup
|
||||
os.Unsetenv("JOB_URL")
|
||||
os.Unsetenv("BUILD_URL")
|
||||
})
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user