Skip to content

Commit d3246f2

Browse files
authored
Merge pull request #444 from codacy/skip-external-tools-analysis
fix: Skip standalone tools from analysis CY-5812
2 parents 8c955e7 + ad5722a commit d3246f2

File tree

25 files changed

+207
-248
lines changed

25 files changed

+207
-248
lines changed

cli/src/main/scala/com/codacy/analysis/cli/CLIError.scala

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,10 @@ object CLIError {
1515
case AnalyserError.ToolExecutionFailure(toolType, toolName) => CLIError.ToolExecutionFailure(toolType, toolName)
1616
case AnalyserError.ToolNeedsNetwork(toolName) => CLIError.ToolNeedsNetwork(toolName)
1717
case AnalyserError.NonExistingToolInput(toolName) => CLIError.NonExistingToolInput(toolName)
18+
case AnalyserError.StandaloneToolInput(toolName) => CLIError.StandaloneToolInput(toolName)
1819
case AnalyserError.NoActiveToolInConfiguration => CLIError.NoActiveToolInConfiguration
1920
case AnalyserError.NoToolsFoundForFiles => CLIError.NoToolsFoundForFiles
2021
case AnalyserError.FailedToFetchTools(errorMessage) => CLIError.CouldNotGetTools(errorMessage)
21-
case AnalyserError.FailedToFindTool(toolUuid) =>
22-
CLIError.CouldNotGetTools(s"Failure to get tool with UUID: $toolUuid")
2322
case AnalyserError.FailedToListPatterns(toolUuid, errorMessage) =>
2423
CLIError.CouldNotGetTools(s"Failure getting patterns for tool with UUID $toolUuid. Error: $errorMessage")
2524
}
@@ -33,7 +32,14 @@ object CLIError {
3332

3433
override val message: String =
3534
s"""The selected tool "$toolName" is not supported or does not exist.
36-
|Use the --help option to get more information about available tools""".stripMargin
35+
|Use the --help option to get more information about available tools""".stripMargin
36+
}
37+
38+
final case class StandaloneToolInput(toolName: String) extends CLIError {
39+
40+
override val message: String =
41+
s"""The selected tool "$toolName" is standalone and can't be run in the CLI.
42+
|Check https://docs.codacy.com/related-tools/local-analysis/client-side-tools for more info.""".stripMargin
3743
}
3844

3945
final case class NonExistentToolsFromRemoteConfiguration(tools: Set[String]) extends CLIError {

cli/src/main/scala/com/codacy/analysis/cli/analysis/AnalyseExecutor.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import scala.sys.process.Process
2222
import scala.util.{Failure, Success, Try}
2323

2424
class AnalyseExecutor(formatter: Formatter,
25-
analyser: Analyser[Try],
25+
analyser: Analyser,
2626
fileCollector: FileCollector[Try],
2727
configuration: CLIConfiguration.Analysis,
2828
toolSelector: ToolSelector) {

cli/src/main/scala/com/codacy/analysis/cli/analysis/ExitStatus.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class ExitStatus(maxAllowedIssues: Int, failIfIncomplete: Boolean = false) {
3838
ExitStatus.ExitCodes.commitsDoNotMatch
3939
case Left(_: CLIError.UncommitedChanges) =>
4040
ExitStatus.ExitCodes.uncommittedChanges
41-
case Left(_: CLIError.NonExistingToolInput) =>
41+
case Left(_: CLIError.NonExistingToolInput | _: CLIError.StandaloneToolInput) =>
4242
ExitStatus.ExitCodes.nonExistentTool
4343
case Left(_: CLIError.UploadError | _: CLIError.MissingUploadRequisites) =>
4444
ExitStatus.ExitCodes.failedUpload

cli/src/main/scala/com/codacy/analysis/cli/analysis/ToolSelector.scala

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,18 @@ class ToolSelector(toolRepository: ToolRepository) {
1313
private val duplicationToolCollector = new DuplicationToolCollector(toolRepository)
1414
private val metricsToolCollector = new MetricsToolCollector(toolRepository)
1515

16-
def allTools(toolInput: Option[String],
16+
def allTools(toolInputOpt: Option[String],
1717
configuration: CLIConfiguration.Tool,
1818
languages: Set[Language]): Either[CLIError, Set[ITool]] = {
19-
20-
def toolsEither = tools(toolInput, configuration, languages)
2119
def duplicationToolsEither =
2220
duplicationToolCollector.fromLanguages(languages).left.map(e => CLIError.CouldNotGetTools(e.message))
2321
def metricsToolsEither =
2422
metricsToolCollector.fromLanguages(languages).left.map(e => CLIError.CouldNotGetTools(e.message))
2523

26-
toolInput match {
24+
toolInputOpt match {
2725
case None =>
2826
for {
29-
tools <- toolsEither
27+
tools <- tools(configuration, languages)
3028
duplicationTools <- duplicationToolsEither
3129
metricsTools <- metricsToolsEither
3230
} yield tools ++ metricsTools ++ duplicationTools
@@ -38,19 +36,16 @@ class ToolSelector(toolRepository: ToolRepository) {
3836
duplicationToolsEither.map(_.map(_.to[ITool]))
3937

4038
case Some("issues") =>
41-
val toolsEither = tools(None, configuration, languages)
39+
val toolsEither = tools(configuration, languages)
4240
toolsEither.map(_.map(_.to[ITool]))
4341

44-
case Some(_) =>
45-
val toolsEither = tools(toolInput, configuration, languages)
46-
toolsEither.map(_.map(_.to[ITool]))
42+
case Some(toolInput) =>
43+
val toolEither = tool(toolInput, languages)
44+
toolEither.map(_.map(_.to[ITool]))
4745
}
4846
}
4947

50-
def tools(toolInput: Option[String],
51-
configuration: CLIConfiguration.Tool,
52-
languages: Set[Language]): Either[CLIError, Set[Tool]] = {
53-
48+
def tools(configuration: CLIConfiguration.Tool, languages: Set[Language]): Either[CLIError, Set[Tool]] = {
5449
def fromRemoteConfig: Either[CLIError, Set[Tool]] = {
5550
configuration.toolConfigurations.left.map(CLIError.NoRemoteProjectConfiguration).flatMap { toolConfiguration =>
5651
val toolUuids = toolConfiguration.filter(_.enabled).map(_.uuid)
@@ -60,19 +55,18 @@ class ToolSelector(toolRepository: ToolRepository) {
6055
.map(_ => CLIError.NonExistentToolsFromRemoteConfiguration(toolUuids))
6156
}
6257
}
63-
6458
def fromLocalConfig: Either[CLIError, Set[Tool]] = {
6559
toolCollector.fromLanguages(languages).left.map(CLIError.from)
6660
}
6761

68-
toolInput.map { toolStr =>
69-
toolCollector.fromNameOrUUID(toolStr, languages).left.map(CLIError.from)
70-
}.getOrElse {
71-
for {
72-
e1 <- fromRemoteConfig.left
73-
e2 <- fromLocalConfig.left
74-
} yield CLIError.CouldNotGetTools(s"${e1.message} and ${e2.message}")
75-
}
62+
for {
63+
e1 <- fromRemoteConfig.left
64+
e2 <- fromLocalConfig.left
65+
} yield CLIError.CouldNotGetTools(s"${e1.message} and ${e2.message}")
66+
}
67+
68+
def tool(toolInput: String, languages: Set[Language]): Either[CLIError, Set[Tool]] = {
69+
toolCollector.fromNameOrUUID(toolInput, languages).left.map(CLIError.from)
7670
}
7771

7872
def fromUuid(uuid: String): Either[AnalyserError, FullToolSpec] = {

cli/src/main/scala/com/codacy/analysis/cli/command/AnalyseCommand.scala

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import com.codacy.analysis.cli.clients.Credentials
1919
import com.codacy.analysis.cli.configuration.{CLIConfiguration, Environment}
2020
import com.codacy.analysis.cli.formatter.Formatter
2121
import com.codacy.analysis.clientapi.tools.ToolsClient
22-
import com.codacy.analysis.core.analysis.Analyser
22+
import com.codacy.analysis.core.analysis.CodacyPluginsAnalyser
2323
import com.codacy.analysis.core.clients.CodacyClient
2424
import com.codacy.analysis.core.configuration.CodacyConfigurationFileLoader
2525
import com.codacy.analysis.core.files.FileCollector
@@ -62,12 +62,7 @@ object AnalyseCommand {
6262
val toolSelector = new ToolSelector(toolRepository(apiUrl))
6363

6464
val analyseExecutor: AnalyseExecutor =
65-
new AnalyseExecutor(
66-
formatter,
67-
Analyser(analyze.extras.analyser),
68-
fileCollector,
69-
configuration.analysis,
70-
toolSelector)
65+
new AnalyseExecutor(formatter, new CodacyPluginsAnalyser(), fileCollector, configuration.analysis, toolSelector)
7166
val uploaderOpt: Either[String, Option[ResultsUploader]] =
7267
ResultsUploader(
7368
codacyClientOpt,
@@ -116,6 +111,10 @@ class AnalyseCommand(analyze: Analyze,
116111
_ <- upload(configuration.upload, analysisResults)
117112
} yield analysisResults
118113

114+
analysisAndUpload.left.foreach { error =>
115+
logger.error(error.message)
116+
}
117+
119118
removeCodacyRuntimeConfigurationFiles(configuration.analysis.projectDirectory)
120119

121120
new ExitStatus(configuration.result.maxAllowedIssues, configuration.result.failIfIncomplete)

cli/src/main/scala/com/codacy/analysis/cli/command/CLIApp.scala

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import caseapp.core.ArgParser
66
import com.codacy.analysis.cli.analysis.ExitStatus
77
import com.codacy.analysis.cli.command.ArgumentParsers._
88
import com.codacy.analysis.cli.formatter.Formatter
9-
import com.codacy.analysis.core.analysis.Analyser
109
import com.codacy.analysis.core.clients.{OrganizationProvider, ProjectName, UserName}
1110
import com.codacy.analysis.core.configuration.AppConfiguration
1211
import com.codacy.analysis.core.git.Commit
@@ -124,10 +123,6 @@ final case class APIOptions(@ValueDescription("The project token.")
124123
@ValueDescription("The codacy api base url.")
125124
codacyApiBaseUrl: Option[String] = Some("https://api.codacy.com"))
126125

127-
final case class ExtraOptions(
128-
@Hidden @ValueDescription(s"The analyser to use. (${Analyser.allAnalysers.map(_.name).mkString(", ")})")
129-
analyser: String = Analyser.defaultAnalyser.name)
130-
131126
final case class Analyze(
132127
@Recurse
133128
options: CommonOptions,
@@ -174,8 +169,8 @@ final case class Analyze(
174169
@ValueDescription(
175170
"Reduce issue severity by one level, for non-security issues, for compatibility with GitHub's code scanning. Use in conjunction with `--format sarif`")
176171
ghCodeScanningCompat: Int @@ Counter = Tag.of(0),
177-
@Recurse
178-
extras: ExtraOptions)
172+
@Hidden // left for backward compatibility
173+
analyser: String = "")
179174
extends CommandOptions {
180175
val uploadValue: Boolean = upload.## > 0
181176
val failIfIncompleteValue: Boolean = failIfIncomplete.## > 0

cli/src/test/scala/com/codacy/analysis/cli/AnalyseExecutorSpec.scala

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import com.codacy.analysis.cli.analysis.{AnalyseExecutor, ToolSelector}
55
import com.codacy.analysis.cli.configuration.CLIConfiguration
66
import com.codacy.analysis.cli.formatter.{Formatter, Json}
77
import com.codacy.analysis.core.ToolRepositoryMock
8-
import com.codacy.analysis.core.analysis.Analyser
8+
import com.codacy.analysis.core.analysis.{Analyser, CodacyPluginsAnalyser}
99
import com.codacy.analysis.core.clients.api._
1010
import com.codacy.analysis.core.files.FileCollector
1111
import com.codacy.analysis.core.model._
@@ -48,7 +48,7 @@ class AnalyseExecutorSpec extends Specification with NoLanguageFeatures with Moc
4848
toolPatterns)),
4949
Set(FilePath(pathToIgnore)))
5050

51-
runAnalyseExecutor(Analyser.defaultAnalyser.name, configuration)
51+
runAnalyseExecutor(configuration)
5252

5353
val result = for {
5454
responseJson <- parser.parse(file.contentAsString)
@@ -95,7 +95,7 @@ class AnalyseExecutorSpec extends Specification with NoLanguageFeatures with Moc
9595
toolPatterns)),
9696
Set.empty)
9797

98-
runAnalyseExecutor(Analyser.defaultAnalyser.name, configuration)
98+
runAnalyseExecutor(configuration)
9999

100100
val result = for {
101101
responseJson <- parser.parse(file.contentAsString)
@@ -141,7 +141,7 @@ class AnalyseExecutorSpec extends Specification with NoLanguageFeatures with Moc
141141
})),
142142
Set.empty)
143143

144-
runAnalyseExecutor(Analyser.defaultAnalyser.name, configuration)
144+
runAnalyseExecutor(configuration)
145145

146146
val result = for {
147147
responseJson <- parser.parse(file.contentAsString)
@@ -161,9 +161,9 @@ class AnalyseExecutorSpec extends Specification with NoLanguageFeatures with Moc
161161
}
162162
}
163163

164-
private def runAnalyseExecutor(analyserName: String, configuration: CLIConfiguration.Analysis) = {
164+
private def runAnalyseExecutor(configuration: CLIConfiguration.Analysis) = {
165165
val formatter: Formatter = Formatter(configuration.output, configuration.projectDirectory)
166-
val analyser: Analyser[Try] = Analyser(analyserName)
166+
val analyser: Analyser = new CodacyPluginsAnalyser()
167167
val fileCollector: FileCollector[Try] = FileCollector.defaultCollector()
168168

169169
val toolRepository = ToolRepositoryMock

cli/src/test/scala/com/codacy/analysis/cli/CLISpec.scala

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,6 @@ class CLISpec extends Specification with NoLanguageFeatures with FileMatchers {
293293
tool = None,
294294
directory = Option(directory),
295295
upload = Tag.of(1),
296-
extras = ExtraOptions(),
297296
toolTimeout = None)
298297

299298
cli.run(analyze) must beEqualTo(ExitStatus.ExitCodes.uncommittedChanges)
@@ -312,7 +311,6 @@ class CLISpec extends Specification with NoLanguageFeatures with FileMatchers {
312311
tool = None,
313312
directory = Option(directory),
314313
upload = Tag.of(1),
315-
extras = ExtraOptions(),
316314
toolTimeout = None)
317315
cli.run(analyze) must beEqualTo(ExitStatus.ExitCodes.uncommittedChanges)
318316
}).get
@@ -333,7 +331,6 @@ class CLISpec extends Specification with NoLanguageFeatures with FileMatchers {
333331
tool = None,
334332
directory = Option(directory),
335333
upload = Tag.of(0),
336-
extras = ExtraOptions(),
337334
toolTimeout = None)
338335

339336
cli.run(analyze) must beEqualTo(ExitStatus.ExitCodes.failedAnalysis)
@@ -352,7 +349,6 @@ class CLISpec extends Specification with NoLanguageFeatures with FileMatchers {
352349
tool = None,
353350
directory = Option(directory),
354351
upload = Tag.of(0),
355-
extras = ExtraOptions(),
356352
commitUuid = Option(Commit.Uuid("Aw geez Rick, this isnt the commit uuid!")),
357353
toolTimeout = None)
358354
cli.run(analyze) must beEqualTo(ExitStatus.ExitCodes.commitsDoNotMatch)
@@ -371,7 +367,6 @@ class CLISpec extends Specification with NoLanguageFeatures with FileMatchers {
371367
tool = None,
372368
directory = Option(directory),
373369
upload = Tag.of(0),
374-
extras = ExtraOptions(),
375370
commitUuid = Option(Commit.Uuid("Aw geez Rick, this isnt the commit uuid!")),
376371
skipCommitUuidValidation = Tag.of(1),
377372
toolTimeout = None)

cli/src/test/scala/com/codacy/analysis/cli/ToolSelectorSpec.scala

Lines changed: 12 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,16 @@ class ToolSelectorSpec extends Specification with NoLanguageFeatures {
3434
needsCompilation = false,
3535
hasConfigFile = true,
3636
configFilenames = Set.empty,
37-
isClientSide = false,
37+
standalone = false,
3838
hasUIConfiguration = true)
3939

40-
override def listTools(): Either[AnalyserError, Seq[ToolSpec]] =
41-
Right(
42-
Seq(
43-
getToolSpec("34225275-f79e-4b85-8126-c7512c987c0d", "PyLint", Set(Python)),
44-
getToolSpec("c6273c22-5248-11e5-885d-feff819cdc9f", "Brakeman", Set(Languages.Ruby)),
45-
getToolSpec("724f98da-f616-4e37-9606-f16919137a1e", "Rubocop", Set(Languages.Ruby)),
46-
getToolSpec("38794ba2-94d8-4178-ab99-1f5c1d12760c", "BundlerAudit", Set(Languages.Ruby)),
47-
getToolSpec("cf05f3aa-fd23-4586-8cce-5368917ec3e5", "ESLint", Set(Languages.Javascript))))
40+
override val allTools = Right(
41+
Seq(
42+
getToolSpec("34225275-f79e-4b85-8126-c7512c987c0d", "PyLint", Set(Python)),
43+
getToolSpec("c6273c22-5248-11e5-885d-feff819cdc9f", "Brakeman", Set(Languages.Ruby)),
44+
getToolSpec("724f98da-f616-4e37-9606-f16919137a1e", "Rubocop", Set(Languages.Ruby)),
45+
getToolSpec("38794ba2-94d8-4178-ab99-1f5c1d12760c", "BundlerAudit", Set(Languages.Ruby)),
46+
getToolSpec("cf05f3aa-fd23-4586-8cce-5368917ec3e5", "ESLint", Set(Languages.Javascript))))
4847

4948
override def listPatterns(tool: ToolSpec): Either[AnalyserError, Seq[PatternSpec]] = Right(Seq.empty)
5049

@@ -74,40 +73,13 @@ class ToolSelectorSpec extends Specification with NoLanguageFeatures {
7473
}
7574

7675
"AnalyseExecutor.tools" should {
77-
"use input over remote configuration" in {
78-
79-
val expectedToolName = "PyLint"
80-
val toolConfigs =
81-
Set(CLIConfiguration.IssuesTool("InvalidToolName", enabled = true, notEdited = false, Set.empty))
82-
val toolConfiguration =
83-
CLIConfiguration.Tool(Option.empty, allowNetwork = false, Right(toolConfigs), Option.empty, Map.empty)
84-
val userInput = Some(expectedToolName)
85-
86-
val toolEither =
87-
toolSelector.tools(userInput, toolConfiguration, Set(Python))
88-
toolEither must beRight
89-
toolEither must beLike {
90-
case Right(toolSet) =>
91-
toolSet.size mustEqual 1
92-
toolSet.head.name mustEqual expectedToolName
93-
}
94-
}
95-
9676
"fail on incorrect input (even if remote configuration is valid)" in {
9777

9878
val expectedToolName = "SomeInvalidTool"
9979

100-
val userInput = Some(expectedToolName)
101-
val toolConfigs =
102-
Set(
103-
CLIConfiguration
104-
.IssuesTool("34225275-f79e-4b85-8126-c7512c987c0d", enabled = true, notEdited = false, Set.empty))
105-
val toolConfiguration =
106-
CLIConfiguration.Tool(Option.empty, allowNetwork = false, Right(toolConfigs), Option.empty, Map.empty)
10780
val languages = LanguagesHelper.fromFileTarget(emptyFilesTarget, Map.empty)
10881

109-
val toolEither =
110-
toolSelector.tools(userInput, toolConfiguration, languages)
82+
val toolEither = toolSelector.tool(expectedToolName, languages)
11183
toolEither must beLeft(CLIError.NonExistingToolInput(expectedToolName))
11284
}
11385

@@ -116,7 +88,6 @@ class ToolSelectorSpec extends Specification with NoLanguageFeatures {
11688
val expectedToolUuid1 = "34225275-f79e-4b85-8126-c7512c987c0d"
11789
val expectedToolUuid2 = "cf05f3aa-fd23-4586-8cce-5368917ec3e5"
11890

119-
val userInput = None
12091
val toolConfigs =
12192
Set(
12293
CLIConfiguration.IssuesTool(expectedToolUuid1, enabled = true, notEdited = false, Set.empty),
@@ -126,8 +97,7 @@ class ToolSelectorSpec extends Specification with NoLanguageFeatures {
12697
val toolConfiguration =
12798
CLIConfiguration.Tool(Option.empty, allowNetwork = false, Right(toolConfigs), Option.empty, Map.empty)
12899

129-
val toolEither =
130-
toolSelector.tools(userInput, toolConfiguration, Set(Javascript, Python))
100+
val toolEither = toolSelector.tools(toolConfiguration, Set(Javascript, Python))
131101
toolEither must beRight
132102
toolEither must beLike {
133103
case Right(toolSet) =>
@@ -137,14 +107,13 @@ class ToolSelectorSpec extends Specification with NoLanguageFeatures {
137107
}
138108

139109
"fallback to finding tools if remote configuration is not present" in {
140-
val userInput = None
141110
val toolConfigs = Left("some error")
142111
val filesTarget = FilesTarget(File(""), Set(File("SomeClazz.rb").path), Set.empty)
143112
val toolConfiguration =
144113
CLIConfiguration.Tool(Option.empty, allowNetwork = false, toolConfigs, Option.empty, Map.empty)
145114
val languages = LanguagesHelper.fromFileTarget(filesTarget, Map.empty)
146115

147-
val toolEither = toolSelector.tools(userInput, toolConfiguration, languages)
116+
val toolEither = toolSelector.tools(toolConfiguration, languages)
148117
toolEither must beRight
149118
toolEither must beLike {
150119
case Right(toolSet) =>
@@ -153,15 +122,14 @@ class ToolSelectorSpec extends Specification with NoLanguageFeatures {
153122
}
154123

155124
"fallback to finding tools (with custom extensions) if remote configuration is not present" in {
156-
val userInput = None
157125
val toolConfigs = Left("some error")
158126
val filesTarget = FilesTarget(File(""), Set(File("SomeClazz.rawr").path), Set.empty)
159127
val languageExtensions: Map[Language, Set[String]] = Map(Languages.Ruby -> Set("rawr"))
160128
val toolConfiguration =
161129
CLIConfiguration.Tool(Option.empty, allowNetwork = true, toolConfigs, Option.empty, languageExtensions)
162130
val languages = LanguagesHelper.fromFileTarget(filesTarget, languageExtensions)
163131

164-
val toolEither = toolSelector.tools(userInput, toolConfiguration, languages)
132+
val toolEither = toolSelector.tools(toolConfiguration, languages)
165133
toolEither must beRight
166134
toolEither must beLike {
167135
case Right(toolSet) =>

0 commit comments

Comments
 (0)