diff --git a/.github/workflows/sonar-evidence-example.yml b/.github/workflows/sonar-evidence-example.yml index 8f47541..fd8ae29 100644 --- a/.github/workflows/sonar-evidence-example.yml +++ b/.github/workflows/sonar-evidence-example.yml @@ -6,8 +6,8 @@ on: branches: - CCS-2-Additional_evidence_examples pull_request: - branches: - - CCS-2-Additional_evidence_examples + branches: + - CCS-2-Additional_evidence_examples permissions: id-token: write contents: read @@ -25,56 +25,30 @@ jobs: echo "Job name: $GITHUB_JOB" - name: Install jfrog cli - id: setup-cli + id: setup-cli uses: jfrog/setup-jfrog-cli@v4 env: JF_URL: ${{ vars.ARTIFACTORY_URL }} with: - oidc-provider-name: jfrog-github-oidc + oidc-provider-name: jfrog-github-oidc + version: latest - uses: actions/checkout@v4 - - name: Install SonarQube Scanner - run: | - curl -sL -sSLo sonar-scanner.zip https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-6.2.1.4610.zip - unzip sonar-scanner.zip - export PATH=$PATH:$PWD/sonar-scanner-6.2.1.4610/bin - pwd - ls -l $PWD/sonar-scanner-6.2.1.4610/bin/ - echo "$PWD/sonar-scanner-6.2.1.4610/bin" - - name: Set up JDK 17 - uses: actions/setup-java@v4 - with: - java-version: '21' # Specify the desired Java version here - distribution: 'temurin' # You can also use 'temurin', 'zulu', etc. - - - name: Run SonarScanner - id: run-sonar-scanner + - name: Sonar scan + uses: SonarSource/sonarqube-scan-action@v5 + continue-on-error: true # Don't fail build on SonarCloud quality gate issues env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - run: | - $PWD/sonar-scanner-6.2.1.4610/bin/sonar-scanner \ - -Dsonar.projectKey=test-evidence \ - -Dsonar.organization=my-evidence-test-org \ - -Dsonar.host.url=https://sonarcloud.io \ - -Dsonar.java.jdkHome=$JAVA_HOME \ - -Dsonar.verbose=true \ - -Dsonar.token=$SONAR_TOKEN - # create evidence from sonar-scan analysis - set +e - # --FailOnAnalysisFailure causes a failure on gateway-failed sonar analysis - ./examples/sonar-scan/bin/sonar-scan-extractor-linux-amd64 --reportTaskFile=$PWD/.scannerwork/report-task.txt > predicate.json - EXIT_CODE=$? - set -e - # write the exit code to the github output so that it can be used in the evidence creation step - echo "------predicate.json------" - cat predicate.json - echo "------sonar-scan.log------" - cat sonar-scan.log - echo "------EXIT------" - echo "create-sonar-evidence=$EXIT_CODE" - echo "create-sonar-evidence=$EXIT_CODE" >> $GITHUB_OUTPUT - + with: + args: > + -Dsonar.projectKey=my-evidence-test-org1_evidence-example + -Dsonar.organization=my-evidence-test-org1 + -Dsonar.projectBaseDir=examples/sonar-scan + -Dsonar.sources=. + -Dsonar.inclusions=**/*.go + -Dsonar.java.jdkHome=$JAVA_HOME + -Dsonar.verbose=true - name: Log in to Artifactory Docker Registry uses: docker/login-action@v3 @@ -109,14 +83,14 @@ jobs: jf rt build-publish - name: Create evidence - if: ${{ steps.run-sonar-scanner.outputs.create-sonar-evidence == 0 }} - run: | + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + SONAR_REPORT_TASK_FILE: ${{ github.workspace }}/examples/sonar-scan/.scannerwork/report-task.txt + run: | # Attach evidence onto build using JFrog CLI jf evd create \ + --integration sonar \ --build-name $GITHUB_WORKFLOW \ --build-number "${{ github.run_number }}" \ - --predicate ./predicate.json \ - --predicate-type https://jfrog.com/evidence/sonar-scan/v1 \ - --provider-id "sonar" \ - --key "${{ secrets.JIRA_TEST_PKEY }}" \ - --key-alias ${{ vars.JIRA_TEST_KEY }} \ No newline at end of file + --key "${{ secrets.EVIDENCE_SIGNING_KEY }}" \ + --key-alias "${{ vars.EVIDENCE_PUBLIC_KEY_ALIAS }}" diff --git a/examples/sonar-scan/README.md b/examples/sonar-scan/README.md index 6f00aa2..67a6261 100644 --- a/examples/sonar-scan/README.md +++ b/examples/sonar-scan/README.md @@ -1,61 +1,75 @@ -# Create Sonar Scan Evidence predicate from the build CI and attach it to the build info -Sonar is a code scanning tool that helps to identify bugs, vulnerabilities, and code smells in your code. -It is important to track the code quality and security of the code changes done and released. -To allow automation of proper code quality and security checks, we create an evidence of the Sonar scan results -during the build with confirmation that the code quality and security checks passed before the code was committed. -using the `FailOnAnalysisFailure` argument the customer can decide if to create the sonar scan evidence if the scan did not pass -sonar quality gates, or fail the predicate creation with exist status 1. -If the Analysis status is not 'OK', but `FailOnAnalysisFailure` was not set, then the predicate is created with analysis.status = 'ERROR' which -should be checked using a policy. - -## Environment variables -- `SONAR_TOKEN` - The sonar server token. -- `SONAR_TYPE` - Should be Either SAAS or SELFHOSTED, defaulting to SAAS. -- `SONAR_HOST_URL` - The sonar server host name, for example https://mysonar.mycorp.com, for example sonar.myconpany.org. required for SELFHOSTED type, if not provided for SAAS type sonarcloud.io is used as default. -- `SONAR_PROXY_URL` - The proxy server URL, in the format of http://your-proxy-server:port. or https://username:password@your-proxy-server:port - -## Arguments -`--reportTaskFile=` - The path to the sonar report task file. -`--FailOnAnalysisFailure` - Fail with exit code 1 if the sonar analysis failed in sonar quality gate. -`--WaitTime=` - between sonar analysis results checks> -`--MaxRetries=` - The maximum number of retries to check the sonar analysis results. -`--UseProxy` - Use a proxy server URL, requires PROXY_URL environment variable to be set. - -## The example is based on the following steps: -1. set sonar token as an environment variable -2. call sonar scan -for example: -`` -$PWD/sonar-scanner-6.2.1.4610/bin/sonar-scanner \ - -Dsonar.projectKey=my-sonar-project-key \ - -Dsonar.organization=my-sonar-org \ - -Dsonar.host.url=https://sonarcloud.io \ - -Dsonar.java.jdkHome=$JAVA_HOME \ - -Dsonar.verbose=true \ - -Dsonar.token=$SONAR_TOKEN -`` -3. call the jira-transition-checker utility (use the binary for your build platform) with these arguments: "transition name" JIRA-ID [,JIRA-ID] -for example: - ``./examples/sonar-scan/bin/sonar-scan-extractor-linux-amd64 --reportTaskFile=$PWD/.scannerwork/report-task.txt --FailOnAnalysisFailure > predicate.json -`` -4. call the evidence create cli with the predicate.json file -for example: -`` -jf evd create \ - --build-name $GITHUB_WORKFLOW \ - --build-number "${{ github.run_number }}" \ - --predicate ./predicate.json \ - --predicate-type https://jfrog.com/evidence/sonar-scan/v1 \ - --provider-id "sonar" \ - --key "${{ secrets.JIRA_TEST_PKEY }}" \ - --key-alias ${{ vars.JIRA_TEST_KEY }} -`` - -## Additional considerations -```plaintext -It is advised to decide if to create an evidence with sonar analysis failure scan or refrain from creating the evidence. -to create the evidence with an analysis gateway failure content, do **not** add the `--FailOnAnalysisFailure` argument. - -to refrain from creating the evidence with an analysis gateway failure content, add the `--FailOnAnalysisFailure` argument. -then check the exit code of the script and decide if to create the evidence or not. -``` \ No newline at end of file +## Sonar evidence creation + +This example shows how to create and attach Sonar analysis evidence using the JFrog CLI. + +### Prerequisites +- SONAR_TOKEN: SonarCloud/SonarQube token. +- A completed Sonar scan that produced a `report-task.txt` file. + +### Default report-task.txt discovery +When you run: +```bash +jf evd create --integration sonar +``` +the tool auto-detects the Sonar task file using these paths (in order): +- target/sonar/report-task.txt (Maven) +- build/sonar/report-task.txt (Gradle) +- .scannerwork/report-task.txt (CLI scanner) +- .sonarqube/out/.sonar/report-task.txt (MSBuild) + +If the file is not found, configure its location via YAML or env var (see below). + +### Minimal workflow step (example) +```yaml +- name: Create evidence + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + run: | + jf evd create \ + --build-name $GITHUB_WORKFLOW \ + --build-number "${{ github.run_number }}" \ + --key "${{ secrets.SIGNING_KEY }}" \ + --key-alias ${{ vars.SIGNING_KEY_ALIAS }} \ + --integration sonar +``` + +### Configuration +You can configure the integration via YAML or environment variables. YAML keys have 1:1 env equivalents. + +1) YAML: .jfrog/evidence/evidence.yml +```yaml +sonar: + url: https://sonarcloud.io + reportTaskFile: .scannerwork/report-task.txt + pollingMaxRetries: 30 + pollingRetryIntervalMs: 5000 +``` + +2) Environment variables +- SONAR_URL +- SONAR_REPORT_TASK_FILE +- SONAR_POLLING_MAX_RETRIES +- SONAR_POLLING_RETRY_INTERVAL_MS + +### Parameters reference +Evidence creation: + +- --integration sonar + - Selects the Sonar integration. + +Sonar resolution (via YAML/env): + +- sonar.url / SONAR_URL + - Sonar base URL. By default url is parsed from report-task.txt. If not found there, defaults to https://sonarcloud.io. + +- sonar.reportTaskFile / SONAR_REPORT_TASK_FILE + - Path to report-task.txt. If omitted, auto-detection (see order above) is used. + +- sonar.pollingMaxRetries / SONAR_POLLING_MAX_RETRIES + - Maximum polling attempts to wait for analysis results. + +- sonar.pollingRetryIntervalMs / SONAR_POLLING_RETRY_INTERVAL_MS + - Milliseconds to wait between polling attempts. + +### Behavior +Evidence is created for both successful and failed Sonar analyses (including failed quality gates). diff --git a/examples/sonar-scan/build-binary.sh b/examples/sonar-scan/build-binary.sh deleted file mode 100755 index 63a8675..0000000 --- a/examples/sonar-scan/build-binary.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env bash - -# Script inspired by https://www.digitalocean.com/community/tutorials/how-to-build-go-executables-for-multiple-platforms-on-ubuntu-16-04 - -errorExit () { - echo; echo "ERROR: $1"; echo - exit 1 -} - -BIN=sonar-scan-extractor -rm -rf bin -mkdir -p bin - -echo "Building $BIN" -#platforms=("darwin/amd64" "linux/arm64" "linux/amd64" "windows/amd64" "windows/386") -platforms=("linux/arm64" "linux/amd64" "darwin/arm64" ) - -for p in "${platforms[@]}"; do - platform_array=(${p//\// }) - GOOS=${platform_array[0]} - GOARCH=${platform_array[1]} - - echo -e "\nBuilding" - echo "OS: $GOOS" - echo "ARCH: $GOARCH" - final_name=$BIN'-'$GOOS'-'$GOARCH - if [ "$GOOS" = "windows" ]; then - final_name+='.exe' - fi - - env GOOS="$GOOS" GOARCH="$GOARCH" go build -o bin/$final_name . || errorExit "Building $final_name failed" -done - -echo -e "\nDone!\nThe following binaries were created in the bin/ directory:" -ls -1 bin/ -echo \ No newline at end of file diff --git a/examples/sonar-scan/main.go b/examples/sonar-scan/main.go index bf8b3b2..52a7925 100644 --- a/examples/sonar-scan/main.go +++ b/examples/sonar-scan/main.go @@ -1,173 +1,9 @@ package main -import ( - "context" - "encoding/json" - "os" - "log" - "time" - "strings" - "strconv" - ) - /* - SonarScanResponse is the json analysis that was outputed by sonar - and will be returned to the calling build process for cresting an evidence - - notice that the calling client should first check that return value was 0 before using the response JSON, - otherwise the response is an error message which cannot be parsed - */ -// sonar response struct -type SonarResponse struct { - Task SonarTask `json:"task"` - Analysis ProjectStatus `json:"analysis"` -} - -// Define a struct to hold the response data -type SonarTaskResponse struct { - Task SonarTask `json:"task"` -} - -type SonarTask struct { - id string `json:"id"` - Status string `json:"status"` - AnalysisId string `json:"analysisId"` - ComponentId string `json:"componentId"` - ComponentKey string `json:"componentKey"` - ComponentName string `json:"componentName"` - Organization string `json:"organization"` - SubmittedAt string `json:"submittedAt"` - SubmitterLogin string `json:"submitterLogin"` - StartedAt string `json:"startedAt"` - ExecutedAt string `json:"executedAt"` - } -type Condition struct { - Status string `json:"status"` - MetricKey string `json:"metricKey"` - Comparator string `json:"comparator"` - PeriodIndex int `json:"periodIndex"` - ErrorThreshold string `json:"errorThreshold"` - ActualValue string `json:"actualValue"` -} - -type Period struct { - Index int `json:"index"` - Mode string `json:"mode"` - Date string `json:"date"` -} -type ProjectStatus struct { - Status string `json:"status"` - Conditions []Condition `json:"conditions"` - Periods []Period `json:"periods"` - IgnoredConditions bool `json:"ignoredConditions"` -} - -type SonarAnalysis struct { - ProjectStatus ProjectStatus `json:"projectStatus"` -} - -const ( - DEFAULT_HTTP_TIMEOUT = 10 * time.Second - LOG_FILE_LOCATION = "sonar-scan.log" +import ( + "fmt" ) -func main() { - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) - defer cancel() - - logFile, err := os.OpenFile(LOG_FILE_LOCATION, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) - if err != nil { - log.Fatal(err) - } - defer logFile.Close() - logger := log.New(logFile, "[SONAR EVIDENCE CREATION] ", log.Ldate|log.Ltime|log.Lshortfile) - logger.Println("Running sonar analysis extraction") - sonar_token := os.Getenv("SONAR_TOKEN") - if sonar_token == "" { - logger.Println("Sonar token not found, set SONAR_TOKEN variable") - os.Exit(1) - } - sonar_type := os.Getenv("SONAR_TYPE") - if sonar_type == "" { - sonar_type = "SAAS" - } else if sonar_type != "SELFHOSTED" && sonar_type != "SAAS" { - logger.Println("Wrong Sonar type, set SONAR_TYPE variable to either SAAS or SELFHOSTED") - os.Exit(1) - } - - //home/runner/work/Evidence-Examples/Evidence-Examples/.scannerwork/report-task.txt - //get the sonar report file location or details to .scannerwork/.report-task.txt - reportTaskFile := ".scannerwork/.report-task.txt" - failOnAnalysisFailure := false - maxRetries := 1 - waitTime := 5 - proxyURL := "" - if len(os.Args) > 0 { - // loop over all args - for i, arg := range os.Args { - if i == 0 { - continue - } - if strings.HasPrefix(arg, "--reportTaskFile=") { - reportTaskFile = strings.TrimPrefix(arg, "--reportTaskFile=") - } else if strings.HasPrefix(arg, "--FailOnAnalysisFailure") { - failOnAnalysisFailure = true - } else if strings.HasPrefix(arg, "--MaxRetries=") { - maxRetriesStr := strings.TrimPrefix(arg, "--MaxRetries=") - maxRetries, err = strconv.Atoi(maxRetriesStr) - if err != nil { - logger.Println("Invalid wait time argument:",maxRetriesStr , "error:" ,err) - os.Exit(1) - } - } else if strings.HasPrefix(arg, "--WaitTime=") { - waitTimeStr := strings.TrimPrefix(arg, "--WaitTime=") - waitTime, err = strconv.Atoi(waitTimeStr) - if err != nil { - logger.Println("Invalid wait time argument:",waitTimeStr , "error:" ,err) - os.Exit(1) - } - } else if strings.HasPrefix(arg, "--UseProxy") { - proxyURL = os.Getenv("SONAR_PROXY_URL") - - if proxyURL == "" { - logger.Println("SONAR_PROXY_URL not found, set SONAR_PROXY_URL variable when using --UseProxy argument") - os.Exit(1) - } - } - } - logger.Println("reportTaskFile:", reportTaskFile) - logger.Println("FailOnAnalysisFailure:", failOnAnalysisFailure) - logger.Println("maxRetries:", maxRetries) - logger.Println("WaitTime:", waitTime) - } - response := SonarResponse{} - defaultSonarHost := "https://sonarcloud.io" - sonarHost := os.Getenv("SONAR_HOST_URL") - if sonar_type == "SAAS" { - if sonarHost == "" { - sonarHost = defaultSonarHost - } - logger.Println("Running sonar analysis extraction for SAAS, host:", sonarHost) - - }else if sonar_type == "SELFHOSTED" { - if sonarHost == "" { - logger.Println("Sonar host not found, set SONAR_HOST_URL variable") - os.Exit(1) - } - logger.Println("Running sonar analysis extraction for " , sonar_type, " server", sonarHost) - } - response, err = runReport(ctx, logger, sonarHost, proxyURL, sonar_token, reportTaskFile, failOnAnalysisFailure, maxRetries, waitTime) - - if err != nil { - logger.Println("Error in generating report predicate:", err) - os.Exit(1) - } - - // marshal the response to JSON - jsonBytes, err := json.Marshal(response) - if err != nil { - logger.Println("Error marshaling JSON", err) - os.Exit(1) - } - // return response to caller through stdout - os.Stdout.Write(jsonBytes) - } +func main() { + fmt.Println("hello world") +} diff --git a/examples/sonar-scan/sonar-helper.go b/examples/sonar-scan/sonar-helper.go deleted file mode 100644 index d31d896..0000000 --- a/examples/sonar-scan/sonar-helper.go +++ /dev/null @@ -1,202 +0,0 @@ -package main -import ( - "context" - "encoding/json" - "os" - "fmt" - "io" - "log" - "net/http" - "time" - "bufio" - "strings" - "net/url" - ) - -const ( - SELFHOSTED_ANALYSIS_URL = "$sonarhost/api/qualitygates/project_status?analysisId=$analysisId" - -) -func runReport(ctx context.Context, logger *log.Logger, sonarHost string, proxyURL string, sonar_token string, reportTaskFile string, failOnAnalysisFailure bool, maxRetries int, waitTime int) (SonarResponse, error) { - logger.Println("Running sonar analysis extraction") - - // fmt.Println("reportTaskFile: ", reportTaskFile) - // Open the reportTaskFile - file, err := os.Open(reportTaskFile) - if err != nil { - logger.Println("Error opening file:", reportTaskFile, "error:", err) - return SonarResponse{}, fmt.Errorf("Error opening file:", reportTaskFile, "error:", err) - } - defer file.Close() - ceTaskUrl:="" - - // Read the file line by line - scanner := bufio.NewScanner(file) - for scanner.Scan() { - line := scanner.Text() - // Skip empty lines and comments - if len(line) == 0 || strings.HasPrefix(line, "#") { - continue - } - // Split the line into key and value - parts := strings.SplitN(line, "=", 2) - if len(parts) == 2 { - key := strings.TrimSpace(parts[0]) - value := strings.TrimSpace(parts[1]) - if key == "ceTaskUrl" { - ceTaskUrl = value - break - } - } - } - if err := scanner.Err(); err != nil { - logger.Println("Error reading file:", reportTaskFile , "error", err) - return SonarResponse{}, fmt.Errorf("Error reading file:", reportTaskFile , "error", err) - } - if ceTaskUrl == "" { - fmt.Printf("ceTaskUrl Key not found") - return SonarResponse{}, fmt.Errorf("ceTaskUrl Key not found") - } - - // Add a reusable HTTP client - var transport *http.Transport - - if proxyURL != "" { - logger.Println("Using proxy url") - proxy, err := url.Parse(proxyURL) - if err != nil { - log.Fatal(err) - } - transport = &http.Transport{ - Proxy: http.ProxyURL(proxy), - MaxIdleConns: 100, - IdleConnTimeout: 30 * time.Second, - DisableCompression: true, - } - }else { - transport = &http.Transport{ - MaxIdleConns: 100, - IdleConnTimeout: 30 * time.Second, - DisableCompression: true, - } - } - - var client = &http.Client{ - Timeout: DEFAULT_HTTP_TIMEOUT, - Transport: transport, - } - - logger.Println("ceTaskUrl", ceTaskUrl) - // get the report task - retries := 0 - - var taskResponse SonarTaskResponse - for retries < maxRetries { - taskResponse, err = getReport(ctx, client, logger, ceTaskUrl, sonar_token ) - if err != nil { - logger.Println("Error getting sonar report task", err) - return SonarResponse{}, fmt.Errorf("Error getting sonar report task", err) - } - if taskResponse.Task.Status == "SUCCESS" { - logger.Println("Sonar analysis task completed successfully after ", retries, " retries") - break - } - if taskResponse.Task.Status == "PENDING" || taskResponse.Task.Status == "IN_PROGRESS" { - logger.Println("Sonar analysis task is still in progress, waiting for ", waitTime, " seconds before retrying") - time.Sleep(time.Duration(waitTime) * time.Second) - retries++ - } - } - if (taskResponse.Task.Status != "SUCCESS") { - logger.Println("Sonar analysis task after ", maxRetries, " retries is ", taskResponse.Task.Status, "exiting") - return SonarResponse{}, fmt.Errorf("Sonar analysis task after ", maxRetries, " retries is ", taskResponse.Task.Status, "exiting") - } - - logger.Println("taskResponse.Task.AnalysisId", taskResponse.Task.AnalysisId) - // get the analysis content - analysis , err := getAnalysis(ctx, client, logger, sonarHost, sonar_token, taskResponse.Task.AnalysisId) - if err != nil { - logger.Println("Error getting sonar analysis report: ", err) - return SonarResponse{}, fmt.Errorf("Error getting sonar analysis report: ", err) - } - if analysis.ProjectStatus.Status != "OK" && failOnAnalysisFailure { - logger.Println("Sonar analysis failed, exiting according to failOnAnalysisFailure argument") - return SonarResponse{}, fmt.Errorf("Sonar analysis failed, exiting according to failOnAnalysisFailure argument") - } - - response := SonarResponse{ - Task: taskResponse.Task, - Analysis: analysis.ProjectStatus, - } - - return response, nil - } - - -func getReport(ctx context.Context , client *http.Client, logger *log.Logger, ceTaskUrl string, sonar_token string) (SonarTaskResponse, error) { - // Make the HTTP GET request - logger.Println("getReport ceTaskUrl:",ceTaskUrl) - req, err := http.NewRequestWithContext(ctx, "GET", ceTaskUrl, nil) - req.Header.Set("Authorization", "Bearer " + sonar_token) - resp, err := client.Do(req) - if err != nil { - return SonarTaskResponse{}, fmt.Errorf("Error making the request, url:",ceTaskUrl, "error", err) - } - - defer resp.Body.Close() - body, err := io.ReadAll(resp.Body) - if err != nil { - logger.Println("getReport error getting response body error:", err) - return SonarTaskResponse{}, fmt.Errorf("getReport error getting response body error, url:",ceTaskUrl, "error", err) - } - - if resp.StatusCode != http.StatusOK { - return SonarTaskResponse{}, fmt.Errorf("getReport error getting response from", ceTaskUrl, " returned ", resp.StatusCode, " response body ", body) - } - - logger.Println("getReport resp.StatusCode:", resp.StatusCode) - - var taskResponse SonarTaskResponse - err = json.Unmarshal(body, &taskResponse) - if err != nil { - logger.Println("getReport error Unmarshal response body ", string(body)) - return SonarTaskResponse{}, fmt.Errorf("error unmarshal report response for report", ceTaskUrl, "error", err) - } - logger.Println("getReport taskResponse:", taskResponse) - return taskResponse, nil -} - -func getAnalysis(ctx context.Context, client *http.Client, logger *log.Logger, sonarHost string, sonar_token string, analysisId string) (SonarAnalysis, error) { - - analysisUrl := strings.Replace(SELFHOSTED_ANALYSIS_URL, "$analysisId", analysisId, 1) - analysisUrl = strings.Replace(analysisUrl, "$sonarhost", sonarHost, 1) - logger.Println("analysisId", analysisId) - logger.Println("sonarhost", sonarHost) - //logger.Println("analysisUrl", analysisUrl) - // Make the HTTP GET request - req, err := http.NewRequestWithContext(ctx, "GET", analysisUrl , nil) - req.Header.Set("Authorization", "Bearer " + sonar_token) - resp, err := client.Do(req) - if err != nil { - return SonarAnalysis{}, fmt.Errorf("getAnalysis, Error making the request, url:",analysisUrl, "error", err) - } - defer resp.Body.Close() - body, err := io.ReadAll(resp.Body) - if err != nil { - logger.Println("getAnalysis error getting response body error:", err) - return SonarAnalysis{}, fmt.Errorf("getAnalysis error getting response body error, url:",analysisUrl, "error", err) - } - - if resp.StatusCode != http.StatusOK { - return SonarAnalysis{}, fmt.Errorf("getAnalysis, error getting response from", analysisUrl, " returned ", resp.StatusCode, " response body ", body) - } - - var analysisResponse SonarAnalysis - err = json.Unmarshal(body, &analysisResponse) - if err != nil { - log.Println("getAnalysis, get temp credentials response body ", string(body)) - return SonarAnalysis{}, fmt.Errorf("getAnalysis, error unmarshal analysis response", analysisUrl, "error", err) - } - - return analysisResponse, nil -} \ No newline at end of file