diff --git a/cmd/sonarExecuteScan.go b/cmd/sonarExecuteScan.go index c116f2041..96014b3df 100644 --- a/cmd/sonarExecuteScan.go +++ b/cmd/sonarExecuteScan.go @@ -1,7 +1,10 @@ package cmd import ( + "fmt" "io/ioutil" + "net" + "net/url" "os" "os/exec" "path" @@ -82,8 +85,27 @@ func sonarExecuteScan(config sonarExecuteScanOptions, _ *telemetry.CustomData, i downloadClient.SetOptions(piperhttp.ClientOptions{TransportTimeout: 20 * time.Second}) // client for talking to the SonarQube API apiClient := &piperhttp.Client{} - //TODO: implement certificate handling - apiClient.SetOptions(piperhttp.ClientOptions{TransportSkipVerification: true}) + proxy := config.Proxy + if proxy != "" { + transportProxy, err := url.Parse(proxy) + if err != nil { + log.Entry().WithError(err).Fatalf("Failed to parse proxy string %v into a URL structure", proxy) + } + host, port, err := net.SplitHostPort(transportProxy.Host) + if err != nil { + log.Entry().WithError(err).Fatalf("Failed to retrieve host and port from the proxy URL") + } + // provide proxy setting for Java based Sonar scanner + javaToolOptions := fmt.Sprintf("-Dhttp.proxyHost=%v -Dhttp.proxyPort=%v", host, port) + os.Setenv("JAVA_TOOL_OPTIONS", javaToolOptions) + + apiClient.SetOptions(piperhttp.ClientOptions{TransportProxy: transportProxy, TransportSkipVerification: true}) + log.Entry().Infof("HTTP client instructed to use %v proxy", proxy) + + } else { + //TODO: implement certificate handling + apiClient.SetOptions(piperhttp.ClientOptions{TransportSkipVerification: true}) + } sonar = sonarSettings{ workingDir: "./", @@ -195,6 +217,14 @@ func runSonar(config sonarExecuteScanOptions, client piperhttp.Downloader, runne log.Entry().WithError(err).Warning("no scan report found") return nil } + + var serverUrl string + + if len(config.Proxy) > 0 { + serverUrl = config.ServerURL + } else { + serverUrl = taskReport.ServerURL + } // write reports JSON reports := []piperutils.Path{ { @@ -215,14 +245,14 @@ func runSonar(config sonarExecuteScanOptions, client piperhttp.Downloader, runne log.Entry().Warn("no measurements are fetched due to missing credentials") return nil } - taskService := SonarUtils.NewTaskService(taskReport.ServerURL, config.Token, taskReport.TaskID, apiClient) + taskService := SonarUtils.NewTaskService(serverUrl, config.Token, taskReport.TaskID, apiClient) // wait for analysis task to complete err = taskService.WaitForTask() if err != nil { return err } // fetch number of issues by severity - issueService := SonarUtils.NewIssuesService(taskReport.ServerURL, config.Token, taskReport.ProjectKey, config.Organization, config.BranchName, config.ChangeID, apiClient) + issueService := SonarUtils.NewIssuesService(serverUrl, config.Token, taskReport.ProjectKey, config.Organization, config.BranchName, config.ChangeID, apiClient) influx.sonarqube_data.fields.blocker_issues, err = issueService.GetNumberOfBlockerIssues() if err != nil { return err @@ -259,7 +289,7 @@ func runSonar(config sonarExecuteScanOptions, client piperhttp.Downloader, runne Info: influx.sonarqube_data.fields.info_issues, }} - componentService := SonarUtils.NewMeasuresComponentService(taskReport.ServerURL, config.Token, taskReport.ProjectKey, config.Organization, config.BranchName, config.ChangeID, apiClient) + componentService := SonarUtils.NewMeasuresComponentService(serverUrl, config.Token, taskReport.ProjectKey, config.Organization, config.BranchName, config.ChangeID, apiClient) cov, err := componentService.GetCoverage() if err != nil { log.Entry().Warnf("failed to retrieve sonar coverage data: %v", err) diff --git a/cmd/sonarExecuteScan_generated.go b/cmd/sonarExecuteScan_generated.go index af229bc0c..db19d3e1d 100644 --- a/cmd/sonarExecuteScan_generated.go +++ b/cmd/sonarExecuteScan_generated.go @@ -23,6 +23,7 @@ import ( type sonarExecuteScanOptions struct { Instance string `json:"instance,omitempty"` + Proxy string `json:"proxy,omitempty"` ServerURL string `json:"serverUrl,omitempty"` Token string `json:"token,omitempty"` Organization string `json:"organization,omitempty"` @@ -238,6 +239,7 @@ func SonarExecuteScanCommand() *cobra.Command { func addSonarExecuteScanFlags(cmd *cobra.Command, stepConfig *sonarExecuteScanOptions) { cmd.Flags().StringVar(&stepConfig.Instance, "instance", os.Getenv("PIPER_instance"), "Jenkins only: The name of the SonarQube instance defined in the Jenkins settings. DEPRECATED: use serverUrl parameter instead") + cmd.Flags().StringVar(&stepConfig.Proxy, "proxy", os.Getenv("PIPER_proxy"), "Proxy URL to be used for communication with the SonarQube instance.") cmd.Flags().StringVar(&stepConfig.ServerURL, "serverUrl", os.Getenv("PIPER_serverUrl"), "The URL to the Sonar backend.") cmd.Flags().StringVar(&stepConfig.Token, "token", os.Getenv("PIPER_token"), "Token used to authenticate with the Sonar Server.") cmd.Flags().StringVar(&stepConfig.Organization, "organization", os.Getenv("PIPER_organization"), "SonarCloud.io only: Organization that the project will be assigned to in SonarCloud.io.") @@ -292,6 +294,15 @@ func sonarExecuteScanMetadata() config.StepData { Aliases: []config.Alias{}, Default: os.Getenv("PIPER_instance"), }, + { + Name: "proxy", + ResourceRef: []config.ResourceReference{}, + Scope: []string{"PARAMETERS", "STEPS", "STAGES"}, + Type: "string", + Mandatory: false, + Aliases: []config.Alias{}, + Default: os.Getenv("PIPER_proxy"), + }, { Name: "serverUrl", ResourceRef: []config.ResourceReference{}, diff --git a/resources/metadata/sonarExecuteScan.yaml b/resources/metadata/sonarExecuteScan.yaml index 8c60fc092..6e124e374 100644 --- a/resources/metadata/sonarExecuteScan.yaml +++ b/resources/metadata/sonarExecuteScan.yaml @@ -23,6 +23,13 @@ spec: - PARAMETERS - STAGES - STEPS + - name: proxy + type: string + description: Proxy URL to be used for communication with the SonarQube instance. + scope: + - PARAMETERS + - STEPS + - STAGES - name: serverUrl aliases: - name: host