internal/platform/ext_gitlab.go (97 lines of code) (raw):

/* * Copyright 2021-2024 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package platform import ( "encoding/json" "fmt" "os" "path/filepath" "github.com/JetBrains/qodana-cli/internal/sarif" log "github.com/sirupsen/logrus" ) // https://docs.gitlab.com/ee/ci/testing/code_quality.html#implement-a-custom-tool const ( // glCodeQualityReport is the name of the GitLab CodeQuality report file glCodeQualityReport = "gl-code-quality-report.json" // codeClimateBlocker = "blocker" codeClimateCritical = "critical" codeClimateMajor = "major" codeClimateMinor = "minor" codeClimateInfo = "info" ) // toCodeClimateSeverity maps SARIF and Qodana severity levels to Code Climate severity levels var toCodeClimateSeverity = map[string]string{ sarifError: codeClimateCritical, sarifWarning: codeClimateMajor, sarifNote: codeClimateMinor, qodanaCritical: codeClimateBlocker, qodanaHigh: codeClimateCritical, qodanaModerate: codeClimateMajor, qodanaLow: codeClimateMinor, qodanaInfo: codeClimateInfo, } // CCIssue represents a Code Climate (GitLab CodeQuality) issue type CCIssue struct { CheckName string `json:"check_name"` Description string `json:"description"` Fingerprint string `json:"fingerprint"` Severity string `json:"severity"` Location Location `json:"location"` } // Location represents a location of the issue type Location struct { Path string `json:"path"` Lines Line `json:"lines"` } // Line represents a line of the issue type Line struct { Begin int `json:"begin"` } type LocationProperties struct { Uri string StartLine int } func extractLocationProperties(r *sarif.Result) *LocationProperties { if r == nil || r.Locations == nil || len(r.Locations) == 0 || r.Locations[0].PhysicalLocation == nil || r.Locations[0].PhysicalLocation.ArtifactLocation == nil || r.Locations[0].PhysicalLocation.Region == nil { return nil } return &LocationProperties{ Uri: r.Locations[0].PhysicalLocation.ArtifactLocation.Uri, StartLine: int(r.Locations[0].PhysicalLocation.Region.StartLine), } } // sarifResultToCodeClimate converts a SARIF result to a code Climate issue. func sarifResultToCodeClimate(r *sarif.Result) CCIssue { loc := Location{ Path: "", Lines: Line{ Begin: 0, }, } locationProperties := extractLocationProperties(r) if locationProperties != nil { loc.Path = locationProperties.Uri loc.Lines.Begin = locationProperties.StartLine } return CCIssue{ CheckName: r.RuleId, Description: r.Message.Text, Fingerprint: getFingerprint(r), Severity: toCodeClimateSeverity[getSeverity(r)], Location: loc, } } // writeGlCodeQualityReport saves GitLab CodeQuality issues to a file in JSON format func writeGlCodeQualityReport(issues []CCIssue, sarifPath string) error { outputFile := filepath.Join(filepath.Dir(sarifPath), glCodeQualityReport) file, err := os.Create(outputFile) if err != nil { log.Warnf("Failed to create GitLab CodeQuality report file: %v", err) } defer func(file *os.File) { err := file.Close() if err != nil { log.Warnf("failed to close GitLab CodeQuality report file: %s", err.Error()) } }(file) encoder := json.NewEncoder(file) if err := encoder.Encode(issues); err != nil { return fmt.Errorf("failed to write GitLab CodeQuality report: %w", err) } return nil }