internal/platform/thirdpartyscan/context.go (169 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 thirdpartyscan import ( "regexp" "github.com/JetBrains/qodana-cli/internal/platform/product" "github.com/JetBrains/qodana-cli/internal/platform/qdyaml" ) const Clang = "clang" const Clt = "clt" type ThirdPartyStartupCloudData struct { LicensePlan string ProjectIdHash string QodanaToken string } // MountInfo is a struct that contains all the helper tools to run a Qodana linter. type MountInfo struct { Converter string Fuser string BaselineCli string CustomTools map[string]string JavaPath string } // LinterInfo is a struct that contains all the information about the linter. type LinterInfo struct { ProductCode string LinterPresentableName string LinterName string LinterVersion string IsEap bool } // Context // // If one has the instance of Context, then it means that it was initialized, and it is in valid state // all mutations should be defined in context_changes.go with names clearly demonstrating the usecase and business logic. // example: scoped script launches two stages of default analysis // // # In the future, you can consider making it an interface // // Yes, there is a lot of boilerplate, and it's ok, it's much better than having one object written and initialized across your program // if I have an object it means it must be in valid state, otherwise it's impossible to reason about the code // // Q: - Why do we prohibit mutations in Context if we pass it by value already? // A: - Because we want to prohibit any unexpected changes to Context at all, imagine at some place the projectDir will // // suddenly change, and pass it further? It's not clear why it was changed? Was it actually initialized at this place? // but it must be initialized already, so we limit all changes, and keep them in context_changes.go // // !!!KEEP IT IMMUTABLE!!! type Context struct { linterInfo LinterInfo mountInfo MountInfo cloudData ThirdPartyStartupCloudData projectDir string resultsDir string reportDir string logDir string cacheDir string clangCompileCommands string clangArgs string property []string cdnetSolution string cdnetProject string cdnetConfiguration string cdnetPlatform string noStatistics bool cdnetNoBuild bool analysisId string baseline string baselineIncludeAbsent bool failThreshold string generateCodeClimateReport bool sendBitBucketInsights bool qodanaYamlConfig QodanaYamlConfig } type QodanaYamlConfig struct { Bootstrap string Version string DotNet qdyaml.DotNet Includes []qdyaml.Clude Excludes []qdyaml.Clude FailThreshold *int FailureConditions qdyaml.FailureConditions } func YamlConfig(yaml qdyaml.QodanaYaml) QodanaYamlConfig { return QodanaYamlConfig{ Bootstrap: yaml.Bootstrap, Version: yaml.Version, DotNet: yaml.DotNet, Includes: yaml.Includes, Excludes: yaml.Excludes, FailThreshold: yaml.FailThreshold, FailureConditions: yaml.FailureConditions, } } type ContextBuilder struct { LinterInfo LinterInfo MountInfo MountInfo CloudData ThirdPartyStartupCloudData ProjectDir string ResultsDir string ReportDir string LogDir string CacheDir string ClangCompileCommands string ClangArgs string Property []string CdnetSolution string CdnetProject string CdnetConfiguration string CdnetPlatform string NoStatistics bool CdnetNoBuild bool AnalysisId string Baseline string BaselineIncludeAbsent bool FailThreshold string GenerateCodeClimateReport bool SendBitBucketInsights bool QodanaYamlConfig QodanaYamlConfig } func (b ContextBuilder) Build() Context { return Context{ linterInfo: b.LinterInfo, mountInfo: b.MountInfo, cloudData: b.CloudData, projectDir: b.ProjectDir, resultsDir: b.ResultsDir, reportDir: b.ReportDir, logDir: b.LogDir, cacheDir: b.CacheDir, clangCompileCommands: b.ClangCompileCommands, clangArgs: b.ClangArgs, property: b.Property, cdnetSolution: b.CdnetSolution, cdnetProject: b.CdnetProject, cdnetConfiguration: b.CdnetConfiguration, cdnetPlatform: b.CdnetPlatform, noStatistics: b.NoStatistics, cdnetNoBuild: b.CdnetNoBuild, analysisId: b.AnalysisId, baseline: b.Baseline, baselineIncludeAbsent: b.BaselineIncludeAbsent, generateCodeClimateReport: b.GenerateCodeClimateReport, sendBitBucketInsights: b.SendBitBucketInsights, failThreshold: b.FailThreshold, qodanaYamlConfig: b.QodanaYamlConfig, } } func (c Context) LinterInfo() LinterInfo { return c.linterInfo } func (c Context) MountInfo() MountInfo { return c.mountInfo } func (c Context) CloudData() ThirdPartyStartupCloudData { return c.cloudData } func (c Context) ProjectDir() string { return c.projectDir } func (c Context) ResultsDir() string { return c.resultsDir } func (c Context) ReportDir() string { return c.reportDir } func (c Context) LogDir() string { return c.logDir } func (c Context) CacheDir() string { return c.cacheDir } func (c Context) ClangCompileCommands() string { return c.clangCompileCommands } func (c Context) ClangArgs() string { return c.clangArgs } func (c Context) CdnetSolution() string { return c.cdnetSolution } func (c Context) CdnetProject() string { return c.cdnetProject } func (c Context) CdnetConfiguration() string { return c.cdnetConfiguration } func (c Context) CdnetPlatform() string { return c.cdnetPlatform } func (c Context) NoStatistics() bool { return c.noStatistics } func (c Context) CdnetNoBuild() bool { return c.cdnetNoBuild } func (c Context) AnalysisId() string { return c.analysisId } func (c Context) Baseline() string { return c.baseline } func (c Context) BaselineIncludeAbsent() bool { return c.baselineIncludeAbsent } func (c Context) FailThreshold() string { return c.failThreshold } func (c Context) GenerateCodeClimateReport() bool { return c.generateCodeClimateReport } func (c Context) SendBitBucketInsights() bool { return c.sendBitBucketInsights } func (c Context) QodanaYamlConfig() QodanaYamlConfig { return c.qodanaYamlConfig } func (c Context) Property() []string { props := make([]string, len(c.property)) copy(props, c.property) return props } func (c Context) IsCommunity() bool { return c.CloudData().LicensePlan == "COMMUNITY" } func (c Context) ClangPath() string { return c.MountInfo().CustomTools[Clang] } func (i LinterInfo) GetMajorVersion() string { re := regexp.MustCompile(`\b\d+\.\d+`) matches := re.FindStringSubmatch(i.LinterVersion) if len(matches) == 0 { return product.ReleaseVersion } return matches[0] }