Skip to content

Commit

Permalink
QD-10856 Create effective configuration in qodana cli
Browse files Browse the repository at this point in the history
- in native mode (or in docker execution) effective configuration is created using `config-loader-cli.jar`, it's passed to linter and used for CLI
- in diff-start, diff-end mode, keep old behaviour (preserve bootstrap from new hash)
- refactor: separate QodanaYamlConfig objects for each context
- config-loader-cli.jar is downloaded by .sh script, verified using checksum file
- functions related to loading of qodana yaml now demonstrate that they don't load effective configuration
- tests
  • Loading branch information
MekhailS committed Feb 22, 2025
1 parent 2b7ec88 commit 72bee51
Show file tree
Hide file tree
Showing 77 changed files with 2,652 additions and 250 deletions.
10 changes: 10 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ jobs:
with:
cache-dependency-path: "**/*.sum"
go-version-file: go.work
- name: Set up Java 17 for config-loader-cli.jar
uses: actions/setup-java@v3
with:
distribution: 'temurin' # Use the Temurin JDK distribution
java-version: '17' # Java version 17
- name: Overwrite tools (to run tests only on gh repo)
run: |
touch cdnet/clt.zip tooling/baseline-cli.jar tooling/intellij-report-converter.jar tooling/qodana-fuser.jar
Expand All @@ -45,6 +50,11 @@ jobs:
)
EOF
shell: bash
- name: Download config-loader-cli.jar
run: |
chmod +x download_deps.sh
./download_deps.sh
shell: bash
- name: Set up gotestfmt
uses: gotesttools/gotestfmt-action@v2
with:
Expand Down
13 changes: 7 additions & 6 deletions cdnet/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,27 +42,28 @@ func (l CdnetLinter) computeCdnetArgs(c thirdpartyscan.Context) ([]string, error
}
props += p
}
dotNet := c.QodanaYamlConfig().DotNet
if c.CdnetConfiguration() != "" {
if props != "" {
props += ";"
}
props += "Configuration=" + c.CdnetConfiguration()
} else if c.QodanaYaml().DotNet.Configuration != "" {
} else if dotNet.Configuration != "" {
if props != "" {
props += ";"
}
props += "Configuration=" + c.QodanaYaml().DotNet.Configuration
props += "Configuration=" + dotNet.Configuration
}
if c.CdnetPlatform() != "" {
if props != "" {
props += ";"
}
props += "Platform=" + c.CdnetPlatform()
} else if c.QodanaYaml().DotNet.Platform != "" {
} else if dotNet.Platform != "" {
if props != "" {
props += ";"
}
props += "Platform=" + c.QodanaYaml().DotNet.Platform
props += "Platform=" + dotNet.Platform
}
mountInfo := c.MountInfo()

Expand Down Expand Up @@ -94,8 +95,8 @@ func getSolutionOrProject(c thirdpartyscan.Context) string {
paths := [4]string{
c.CdnetSolution(),
c.CdnetProject(),
c.QodanaYaml().DotNet.Solution,
c.QodanaYaml().DotNet.Project,
c.QodanaYamlConfig().DotNet.Solution,
c.QodanaYamlConfig().DotNet.Project,
}
for _, path := range paths {
if path != "" {
Expand Down
74 changes: 37 additions & 37 deletions cdnet/options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ import (
"testing"
)

func createDefaultYaml(sln string, prj string, cfg string, plt string) qdyaml.QodanaYaml {
return qdyaml.QodanaYaml{
func createDefaultYaml(sln string, prj string, cfg string, plt string) thirdpartyscan.QodanaYamlConfig {
return thirdpartyscan.QodanaYamlConfig{
DotNet: qdyaml.DotNet{
Solution: sln,
Project: prj,
Expand All @@ -49,20 +49,20 @@ func TestComputeCdnetArgs(t *testing.T) {
{
name: "No solution/project specified",
cb: thirdpartyscan.ContextBuilder{
Property: []string{},
ResultsDir: "",
QodanaYaml: createDefaultYaml("", "", "", ""),
Property: []string{},
ResultsDir: "",
QodanaYamlConfig: createDefaultYaml("", "", "", ""),
},
expectedArgs: nil,
expectedErr: "solution/project relative file path is not specified. Use --solution or --project flags or create qodana.yaml file with respective fields",
},
{
name: "project specified",
cb: thirdpartyscan.ContextBuilder{
Property: []string{},
ResultsDir: "",
CdnetProject: "project",
QodanaYaml: createDefaultYaml("", "", "", ""),
Property: []string{},
ResultsDir: "",
CdnetProject: "project",
QodanaYamlConfig: createDefaultYaml("", "", "", ""),
},
expectedArgs: []string{
"dotnet",
Expand All @@ -78,9 +78,9 @@ func TestComputeCdnetArgs(t *testing.T) {
{
name: "project specified in yaml",
cb: thirdpartyscan.ContextBuilder{
Property: []string{},
ResultsDir: "",
QodanaYaml: createDefaultYaml("", "project", "", ""),
Property: []string{},
ResultsDir: "",
QodanaYamlConfig: createDefaultYaml("", "project", "", ""),
},
expectedArgs: []string{
"dotnet",
Expand All @@ -96,10 +96,10 @@ func TestComputeCdnetArgs(t *testing.T) {
{
name: "solution specified",
cb: thirdpartyscan.ContextBuilder{
Property: []string{},
ResultsDir: "",
CdnetSolution: "solution",
QodanaYaml: createDefaultYaml("", "", "", ""),
Property: []string{},
ResultsDir: "",
CdnetSolution: "solution",
QodanaYamlConfig: createDefaultYaml("", "", "", ""),
},
expectedArgs: []string{
"dotnet",
Expand All @@ -115,9 +115,9 @@ func TestComputeCdnetArgs(t *testing.T) {
{
name: "solution specified",
cb: thirdpartyscan.ContextBuilder{
Property: []string{},
ResultsDir: "",
QodanaYaml: createDefaultYaml("solution", "", "", ""),
Property: []string{},
ResultsDir: "",
QodanaYamlConfig: createDefaultYaml("solution", "", "", ""),
},
expectedArgs: []string{
"dotnet",
Expand All @@ -133,9 +133,9 @@ func TestComputeCdnetArgs(t *testing.T) {
{
name: "configuration specified in yaml",
cb: thirdpartyscan.ContextBuilder{
Property: []string{},
ResultsDir: "",
QodanaYaml: createDefaultYaml("solution", "", "cfg", ""),
Property: []string{},
ResultsDir: "",
QodanaYamlConfig: createDefaultYaml("solution", "", "cfg", ""),
},
expectedArgs: []string{
"dotnet",
Expand All @@ -155,7 +155,7 @@ func TestComputeCdnetArgs(t *testing.T) {
Property: []string{},
ResultsDir: "",
CdnetConfiguration: "cfg",
QodanaYaml: createDefaultYaml("solution", "", "", ""),
QodanaYamlConfig: createDefaultYaml("solution", "", "", ""),
},
expectedArgs: []string{
"dotnet",
Expand All @@ -172,9 +172,9 @@ func TestComputeCdnetArgs(t *testing.T) {
{
name: "platform specified in cfg",
cb: thirdpartyscan.ContextBuilder{
Property: []string{},
ResultsDir: "",
QodanaYaml: createDefaultYaml("solution", "", "", "x64"),
Property: []string{},
ResultsDir: "",
QodanaYamlConfig: createDefaultYaml("solution", "", "", "x64"),
},
expectedArgs: []string{
"dotnet",
Expand All @@ -191,10 +191,10 @@ func TestComputeCdnetArgs(t *testing.T) {
{
name: "platform specified",
cb: thirdpartyscan.ContextBuilder{
Property: []string{},
ResultsDir: "",
CdnetPlatform: "x64",
QodanaYaml: createDefaultYaml("solution", "", "", ""),
Property: []string{},
ResultsDir: "",
CdnetPlatform: "x64",
QodanaYamlConfig: createDefaultYaml("solution", "", "", ""),
},
expectedArgs: []string{
"dotnet",
Expand All @@ -215,7 +215,7 @@ func TestComputeCdnetArgs(t *testing.T) {
ResultsDir: "",
CdnetPlatform: "x64",
CdnetConfiguration: "Debug",
QodanaYaml: createDefaultYaml("solution", "", "", ""),
QodanaYamlConfig: createDefaultYaml("solution", "", "", ""),
},
expectedArgs: []string{
"dotnet",
Expand All @@ -232,10 +232,10 @@ func TestComputeCdnetArgs(t *testing.T) {
{
name: "no-build",
cb: thirdpartyscan.ContextBuilder{
Property: []string{},
ResultsDir: "",
CdnetNoBuild: true,
QodanaYaml: createDefaultYaml("solution", "", "", ""),
Property: []string{},
ResultsDir: "",
CdnetNoBuild: true,
QodanaYamlConfig: createDefaultYaml("solution", "", "", ""),
},
expectedArgs: []string{
"dotnet",
Expand All @@ -261,8 +261,8 @@ func TestComputeCdnetArgs(t *testing.T) {
"idea.diagnostic.opentelemetry.file=/data/results/log/open-telemetry.json",
"jetbrains.security.package-checker.synchronizationTimeout=1000",
},
ResultsDir: "",
QodanaYaml: createDefaultYaml("solution", "", "", ""),
ResultsDir: "",
QodanaYamlConfig: createDefaultYaml("solution", "", "", ""),
},
expectedArgs: []string{
"dotnet",
Expand Down
2 changes: 1 addition & 1 deletion cdnet/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func (l CdnetLinter) ComputeNewLinterInfo(
}

func (l CdnetLinter) RunAnalysis(c thirdpartyscan.Context) error {
utils.Bootstrap(c.QodanaYaml().Bootstrap, c.ProjectDir())
utils.Bootstrap(c.QodanaYamlConfig().Bootstrap, c.ProjectDir())
args, err := l.computeCdnetArgs(c)
if err != nil {
return err
Expand Down
2 changes: 1 addition & 1 deletion clang
Submodule clang updated from cbb59d to 5b48c1
8 changes: 4 additions & 4 deletions cmd/cmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,13 +149,13 @@ func TestInitCommand(t *testing.T) {
t.Fatal(err)
}

filename := qdyaml.FindDefaultQodanaYaml(projectPath)
updatedQodanaYamlPath := qdyaml.GetLocalNotEffectiveQodanaYamlFullPath(projectPath, "")

if filename != "qodana.yml" {
t.Fatalf("expected \"qodana.yml\" got \"%s\"", filename)
if !strings.HasSuffix(updatedQodanaYamlPath, "qodana.yml") {
t.Fatalf("expected \"qodana.yml\" got \"%s\"", updatedQodanaYamlPath)
}

qodanaYaml := qdyaml.LoadQodanaYaml(projectPath, filename)
qodanaYaml := qdyaml.LoadQodanaYamlByFullPath(updatedQodanaYamlPath)

if qodanaYaml.Linter != product.Image(product.QDPY) {
t.Fatalf("expected \"%s\", but got %s", product.Image(product.QDPY), qodanaYaml.Linter)
Expand Down
17 changes: 11 additions & 6 deletions cmd/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,14 @@ func newInitCommand() *cobra.Command {
Short: "Configure a project for Qodana",
Long: `Configure a project for Qodana: prepare Qodana configuration file by analyzing the project structure and generating a default configuration qodana.yaml file.`,
Run: func(cmd *cobra.Command, args []string) {
cliOptions.ConfigName = qdyaml.FindDefaultQodanaYaml(cliOptions.ProjectDir)
qodanaYaml := qdyaml.LoadQodanaYaml(cliOptions.ProjectDir, cliOptions.ConfigName)
localQodanaYamlFullPath := qdyaml.GetLocalNotEffectiveQodanaYamlFullPath(
cliOptions.ProjectDir,
cliOptions.ConfigName,
)
if localQodanaYamlFullPath == "" {
localQodanaYamlFullPath = filepath.Join(cliOptions.ProjectDir, "qodana.yaml")
}
qodanaYaml := qdyaml.LoadQodanaYamlByFullPath(localQodanaYamlFullPath)

ide := qodanaYaml.Ide
linter := qodanaYaml.Linter
Expand All @@ -61,9 +67,8 @@ func newInitCommand() *cobra.Command {
analyzer := commoncontext.GetAnalyzer(cliOptions.ProjectDir, token)

qdyaml.WriteQodanaLinterToYamlFile(
cliOptions.ProjectDir,
localQodanaYamlFullPath,
analyzer,
cliOptions.ConfigName,
product.AllCodes,
)
if product.IsNativeAnalyzer(analyzer) {
Expand All @@ -86,11 +91,11 @@ func newInitCommand() *cobra.Command {
)
}
if msg.IsInteractive() && qodanaYaml.IsDotNet() && (qodanaYaml.DotNet.IsEmpty() || cliOptions.Force) {
if commoncontext.GetAndSaveDotNetConfig(cliOptions.ProjectDir, cliOptions.ConfigName) {
if commoncontext.GetAndSaveDotNetConfig(cliOptions.ProjectDir, localQodanaYamlFullPath) {
msg.SuccessMessage("The .NET configuration was successfully set")
}
}
msg.PrintFile(filepath.Join(cliOptions.ProjectDir, cliOptions.ConfigName))
msg.PrintFile(localQodanaYamlFullPath)

commonCtx := commoncontext.Compute(
linter,
Expand Down
5 changes: 0 additions & 5 deletions cmd/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (
"github.com/JetBrains/qodana-cli/v2025/platform/commoncontext"
"github.com/JetBrains/qodana-cli/v2025/platform/qdcontainer"
"github.com/JetBrains/qodana-cli/v2025/platform/qdenv"
"github.com/JetBrains/qodana-cli/v2025/platform/qdyaml"
"github.com/docker/docker/client"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
Expand All @@ -36,10 +35,6 @@ func newPullCommand() *cobra.Command {
Short: "Pull latest version of linter",
Long: `An alternative to pull an image.`,
Run: func(cmd *cobra.Command, args []string) {
if cliOptions.ConfigName == "" {
cliOptions.ConfigName = qdyaml.FindDefaultQodanaYaml(cliOptions.ProjectDir)
}

commonCtx := commoncontext.Compute(
cliOptions.Linter,
"",
Expand Down
37 changes: 34 additions & 3 deletions cmd/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/JetBrains/qodana-cli/v2025/platform"
"github.com/JetBrains/qodana-cli/v2025/platform/cmd"
"github.com/JetBrains/qodana-cli/v2025/platform/commoncontext"
"github.com/JetBrains/qodana-cli/v2025/platform/effectiveconfig"
"github.com/JetBrains/qodana-cli/v2025/platform/msg"
"github.com/JetBrains/qodana-cli/v2025/platform/qdenv"
"github.com/JetBrains/qodana-cli/v2025/platform/qdyaml"
Expand All @@ -50,8 +51,6 @@ But you can always override qodana.yaml options with the following command-line
Run: func(cmd *cobra.Command, args []string) {
ctx := cmd.Context()

qodanaYaml := qdyaml.LoadQodanaYaml(cliOptions.ProjectDir, cliOptions.ConfigName)

commonCtx := commoncontext.Compute(
cliOptions.Linter,
cliOptions.Ide,
Expand All @@ -67,7 +66,39 @@ But you can always override qodana.yaml options with the following command-line
checkProjectDir(commonCtx.ProjectDir)

preparedHost := startup.PrepareHost(commonCtx)
scanContext := corescan.CreateContext(*cliOptions, commonCtx, preparedHost, qodanaYaml)

effectiveConfigFiles := effectiveconfig.Files{}
qodanaYamlConfig := corescan.QodanaYamlConfig{}
if commonCtx.Ide != "" {
var err error
localQodanaYamlFullPath := qdyaml.GetLocalNotEffectiveQodanaYamlFullPath(
commonCtx.ProjectDir,
cliOptions.ConfigName,
)
effectiveConfigFiles, err = effectiveconfig.CreateEffectiveConfigFiles(
localQodanaYamlFullPath,
cliOptions.GlobalConfigurationsFile,
cliOptions.GlobalConfigurationId,
preparedHost.Prod.JbrJava(),
commonCtx.QodanaSystemDir,
"qdconfig",
commonCtx.LogDir(),
)
if err != nil {
log.Fatalf("Failed to load Qodana configuration %s", err)
}
if effectiveConfigFiles.EffectiveQodanaYamlPath != "" {
yaml := qdyaml.LoadQodanaYamlByFullPath(effectiveConfigFiles.EffectiveQodanaYamlPath)
qodanaYamlConfig = corescan.YamlConfig(yaml)
}
}
scanContext := corescan.CreateContext(
*cliOptions,
commonCtx,
preparedHost,
qodanaYamlConfig,
effectiveConfigFiles.ConfigDir,
)

exitCode := core.RunAnalysis(ctx, scanContext)
if qdenv.IsContainer() {
Expand Down
Loading

0 comments on commit 72bee51

Please sign in to comment.