Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 17 additions & 8 deletions docs/static-code-analysis-tool/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,55 +74,64 @@ bal scan --target-dir="results"
```

4. Run analysis and generate a HTML analysis report.

```bash
bal scan --scan-report
```

5. View all available rules.
5. Run analysis and specify the output format (ballerina or sarif).

```bash
bal scan --format=sarif
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
bal scan --format=sarif
$ bal scan --format=sarif

```

> Note: The default format is ballerina. The tool supports both ballerina and sarif formats for analysis results.

6. View all available rules.

```bash
bal scan --list-rules
```

6. Run analysis for a specific rule.
7. Run analysis for a specific rule.

```bash
bal scan --include-rules="ballerina:101"
```

7. Run analysis for a specific set of rules.
8. Run analysis for a specific set of rules.

```bash
bal scan --include-rules="ballerina:101, ballerina/io:101"
```

8. Exclude analysis for a specific rule.
9. Exclude analysis for a specific rule.

```bash
bal scan --exclude-rules="ballerina:101"
```

9. Exclude analysis for a specific set of rules.
10. Exclude analysis for a specific set of rules.

```bash
bal scan --exclude-rules="ballerina:101, ballerina/io:101"
```

10. Run analysis and report to a static analysis platform (e.g., SonarQube).
11. Run analysis and report to a static analysis platform (e.g., SonarQube).

```bash
bal scan --platforms=sonarqube
```

> Note: If the Platform Plugin path is not provided in a `Scan.toml` file, the tool will attempt to download the Platform Plugin for plugins developed by the Ballerina team.

11. Run analysis and report to multiple static analysis platforms.
12. Run analysis and report to multiple static analysis platforms.

```bash
bal scan --platforms="sonarqube, semgrep, codeql"
```

12. Configuring the tool's behavior using a configuration file. (e.g., `Scan.toml`)
13. Configuring the tool's behavior using a configuration file. (e.g., `Scan.toml`)

```md
📦ballerina_project
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
group=io.ballerina.scan
version=0.10.1-SNAPSHOT
version=0.11.0-SNAPSHOT

# Plugin versions
spotbugsPluginVersion=6.1.5
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package io.ballerina.scan.test;

import io.ballerina.projects.Project;
import io.ballerina.scan.ReportFormat;
import io.ballerina.scan.Rule;

import java.io.PrintStream;
Expand All @@ -37,20 +38,22 @@ public class TestOptions {
private final boolean platformTriggered;
private final String targetDir;
private final boolean scanReport;
private final ReportFormat format;
private final boolean listRules;
private final List<Rule> includeRules;
private final List<Rule> excludeRules;
private final List<String> platforms;

private TestOptions(Project project, PrintStream outputStream, boolean helpFlag, boolean platformTriggered,
String targetDir, boolean scanReport, boolean listRules, List<Rule> includeRules,
List<Rule> excludeRules, List<String> platforms) {
String targetDir, boolean scanReport, ReportFormat format, boolean listRules,
List<Rule> includeRules, List<Rule> excludeRules, List<String> platforms) {
this.project = project;
this.outputStream = outputStream;
this.helpFlag = helpFlag;
this.platformTriggered = platformTriggered;
this.targetDir = targetDir;
this.scanReport = scanReport;
this.format = format;
this.listRules = listRules;
this.includeRules = includeRules;
this.excludeRules = excludeRules;
Expand All @@ -72,9 +75,9 @@ public static TestOptionsBuilder builder(Project project) {
*
* @return the project to be scanned
*/
Project project() {
Project project() {
return project;
}
}

/**
* Get the output stream.
Expand Down Expand Up @@ -121,6 +124,15 @@ boolean scanReport() {
return scanReport;
}

/**
* Get the format of the report.
*
* @return the format of the report
*/
ReportFormat format() {
return format;
}

/**
* Get if the rules should be listed or not.
*
Expand Down Expand Up @@ -164,6 +176,7 @@ public static class TestOptionsBuilder {
private boolean platformTriggered;
private String targetDir;
private boolean scanReport;
private ReportFormat format;
private boolean listRules;
private List<Rule> includeRules = List.of();
private List<Rule> excludeRules = List.of();
Expand All @@ -179,6 +192,7 @@ private TestOptionsBuilder(Project project) {
* @param outputStream the output stream
* @return this builder
*/
@SuppressWarnings("unused")
public TestOptionsBuilder setOutputStream(PrintStream outputStream) {
this.outputStream = outputStream;
return this;
Expand All @@ -190,6 +204,7 @@ public TestOptionsBuilder setOutputStream(PrintStream outputStream) {
* @param helpFlag true if the help flag needs to be enabled, false otherwise
* @return this builder
*/
@SuppressWarnings("unused")
public TestOptionsBuilder setHelpFlag(boolean helpFlag) {
this.helpFlag = helpFlag;
return this;
Expand All @@ -198,9 +213,11 @@ public TestOptionsBuilder setHelpFlag(boolean helpFlag) {
/**
* Set if the scan is triggered by a platform.
*
* @param platformTriggered true if the scan is triggered by a platform, false otherwise
* @param platformTriggered true if the scan is triggered by a platform, false
* otherwise
* @return this builder
*/
@SuppressWarnings("unused")
public TestOptionsBuilder setPlatformTriggered(boolean platformTriggered) {
this.platformTriggered = platformTriggered;
return this;
Expand All @@ -212,6 +229,7 @@ public TestOptionsBuilder setPlatformTriggered(boolean platformTriggered) {
* @param targetDir the target directory
* @return this builder
*/
@SuppressWarnings("unused")
public TestOptionsBuilder setTargetDir(String targetDir) {
this.targetDir = targetDir;
return this;
Expand All @@ -220,20 +238,47 @@ public TestOptionsBuilder setTargetDir(String targetDir) {
/**
* Set if the scan report needs to be enabled.
*
* @param scanReport true if the scan report needs to be enabled, false otherwise
* @param scanReport true if the scan report needs to be enabled, false
* otherwise
* @return this builder
*/
@SuppressWarnings("unused")
public TestOptionsBuilder setScanReport(boolean scanReport) {
this.scanReport = scanReport;
return this;
}

/**
* Set the format of the report.
*
* @param format the format of the report
* @return this builder
*/
@SuppressWarnings("unused")
public TestOptionsBuilder setFormat(ReportFormat format) {
this.format = format;
return this;
}

/**
* Set the format of the report using string value.
*
* @param format the format string value
* @return this builder
*/
@SuppressWarnings("unused")
public TestOptionsBuilder setFormat(String format) {
this.format = ReportFormat.fromString(format);
return this;
}

/**
* Set if the rules should be listed.
*
* @param listRules true if the rules should be listed, false otherwise
* @return this builder
*/
@SuppressWarnings("unused")
public TestOptionsBuilder setListRules(boolean listRules) {
this.listRules = listRules;
return this;
Expand All @@ -245,6 +290,7 @@ public TestOptionsBuilder setListRules(boolean listRules) {
* @param includeRules the list of rules to be included
* @return this builder
*/
@SuppressWarnings("unused")
public TestOptionsBuilder setIncludeRules(List<Rule> includeRules) {
this.includeRules = Collections.unmodifiableList(includeRules);
return this;
Expand All @@ -256,6 +302,7 @@ public TestOptionsBuilder setIncludeRules(List<Rule> includeRules) {
* @param excludeRules the list of rules to be excluded
* @return this builder
*/
@SuppressWarnings("unused")
public TestOptionsBuilder setExcludeRules(List<Rule> excludeRules) {
this.excludeRules = Collections.unmodifiableList(excludeRules);
return this;
Expand All @@ -267,6 +314,7 @@ public TestOptionsBuilder setExcludeRules(List<Rule> excludeRules) {
* @param platforms the list of platforms
* @return this builder
*/
@SuppressWarnings("unused")
public TestOptionsBuilder setPlatforms(List<String> platforms) {
this.platforms = Collections.unmodifiableList(platforms);
return this;
Expand All @@ -277,9 +325,10 @@ public TestOptionsBuilder setPlatforms(List<String> platforms) {
*
* @return the built {@code TestOptions} instance
*/
@SuppressWarnings("unused")
public TestOptions build() {
return new TestOptions(project, outputStream, helpFlag, platformTriggered,
targetDir, scanReport, listRules, includeRules, excludeRules, platforms);
targetDir, scanReport, format, listRules, includeRules, excludeRules, platforms);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
import java.util.Collections;
import java.util.Optional;

import static io.ballerina.scan.ReportFormat.BALLERINA;

/**
* TestScanCmd extends ScanCmd to extend it for testing purposes.
*
Expand All @@ -49,11 +51,11 @@ public class TestScanCmd extends ScanCmd {
options.platformTriggered(),
options.targetDir(),
options.scanReport(),
options.format(),
options.listRules(),
options.includeRules(),
options.excludeRules(),
options.platforms()
);
options.platforms());
this.project = options.project();
}

Expand All @@ -65,11 +67,11 @@ public class TestScanCmd extends ScanCmd {
false,
null,
false,
BALLERINA,
false,
Collections.emptyList(),
Collections.emptyList(),
Collections.emptyList()
);
Collections.emptyList());
if (projectPath.toFile().isDirectory()) {
project = BuildProject.load(getEnvironmentBuilder(distributionPath), projectPath);
} else {
Expand Down
12 changes: 12 additions & 0 deletions scan-command/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,18 @@ tasks.withType(JavaExec).configureEach {
systemProperty 'ballerina.home', System.getenv("BALLERINA_HOME")
}

// Inject version into properties file during build
processResources {
filesMatching('**/version.properties') {
expand(project.properties)
}
doLast {
def versionPropsFile = new File(sourceSets.main.output.resourcesDir, 'version.properties')
versionPropsFile.parentFile.mkdirs()
versionPropsFile.text = "app.version=${version}\n"
}
}

// Setting up checkstyles
tasks.register('downloadCheckstyleRuleFiles', Download) {
src([
Expand Down
60 changes: 60 additions & 0 deletions scan-command/src/main/java/io/ballerina/scan/ReportFormat.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
*
* WSO2 LLC. licenses this file to you 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
*
* http://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 io.ballerina.scan;

/**
* Enum representing the report formats supported by the scan command.
*
* @since 0.11.0
*/
public enum ReportFormat {
BALLERINA("ballerina"),
SARIF("sarif");

private final String format;

ReportFormat(String format) {
this.format = format;
}

/**
* Returns the format string of the report format.
*
* @return the format string
*/
public String getFormat() {
return format;
}

/**
* Returns the ReportFormat enum constant corresponding to the given format string.
*
* @param format the format string
* @return the corresponding ReportFormat enum constant
* @throws IllegalArgumentException if the format string does not match any known format
*/
public static ReportFormat fromString(String format) {
for (ReportFormat reportFormat : values()) {
if (reportFormat.getFormat().equalsIgnoreCase(format)) {
return reportFormat;
}
}
throw new IllegalArgumentException("Unknown report format: " + format);
}
}
Loading
Loading