Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add Nuget support #417

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@ public final class LicenseCheckRulesDefinition implements RulesDefinition {
public static final String LANG_GROOVY = "grvy";
public static final String LANG_KOTLIN = "kotlin";
public static final String LANG_SCALA = "scala";
public static final String LANG_CS = "cs";

public static final String RULE_REPO_KEY = "licensecheck";
public static final String RULE_REPO_KEY_JS = "licensecheck-js";
public static final String RULE_REPO_KEY_TS = "licensecheck-ts";
public static final String RULE_REPO_KEY_GROOVY = "licensecheck-groovy";
public static final String RULE_REPO_KEY_KOTLIN = "licensecheck-kotlin";
public static final String RULE_REPO_KEY_SCALA = "licensecheck-scala";
public static final String RULE_REPO_KEY_CS = "licensecheck-cs";

public static final String RULE_UNLISTED_KEY = "licensecheck.unlisted";
public static final String RULE_NOT_ALLOWED_LICENSE_KEY = "licensecheck.notallowedlicense";
Expand All @@ -34,6 +36,7 @@ public void define(Context context) {
context.createRepository(RULE_REPO_KEY_GROOVY, LANG_GROOVY),
context.createRepository(RULE_REPO_KEY_KOTLIN, LANG_KOTLIN),
context.createRepository(RULE_REPO_KEY_SCALA, LANG_SCALA),
context.createRepository(RULE_REPO_KEY_CS, LANG_CS)
};

for (NewRepository repo : repos) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import static at.porscheinformatik.sonarqube.licensecheck.LicenseCheckRulesDefinition.RULE_REPO_KEY_JS;
import static at.porscheinformatik.sonarqube.licensecheck.LicenseCheckRulesDefinition.RULE_REPO_KEY_KOTLIN;
import static at.porscheinformatik.sonarqube.licensecheck.LicenseCheckRulesDefinition.RULE_REPO_KEY_TS;
import static at.porscheinformatik.sonarqube.licensecheck.LicenseCheckRulesDefinition.RULE_REPO_KEY_CS;
import static java.util.function.Predicate.not;

import at.porscheinformatik.sonarqube.licensecheck.gradle.GradleDependencyScanner;
Expand All @@ -22,6 +23,7 @@
import org.sonar.api.scanner.fs.InputProject;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import at.porscheinformatik.sonarqube.licensecheck.nugetlicense.NugetLicenseDependencyScanner;

public class LicenseCheckSensor implements Sensor {

Expand Down Expand Up @@ -49,6 +51,8 @@ public LicenseCheckSensor(
),
new MavenDependencyScanner(licenseMappingService),
new GradleDependencyScanner(licenseMappingService),
new GradleDependencyScanner(licenseMappingService),
cloud122 marked this conversation as resolved.
Show resolved Hide resolved
new NugetLicenseDependencyScanner(licenseMappingService)
};
}

Expand Down Expand Up @@ -145,7 +149,8 @@ public void describe(SensorDescriptor descriptor) {
RULE_REPO_KEY_JS,
RULE_REPO_KEY_TS,
RULE_REPO_KEY_GROOVY,
RULE_REPO_KEY_KOTLIN
RULE_REPO_KEY_KOTLIN,
RULE_REPO_KEY_CS
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,8 @@ private static String getRepoKey(Dependency dependency) {
return LicenseCheckRulesDefinition.RULE_REPO_KEY_TS;
case LicenseCheckRulesDefinition.LANG_GROOVY:
return LicenseCheckRulesDefinition.RULE_REPO_KEY_GROOVY;
case LicenseCheckRulesDefinition.LANG_CS:
return LicenseCheckRulesDefinition.RULE_REPO_KEY_CS;
case LicenseCheckRulesDefinition.LANG_SCALA:
return LicenseCheckRulesDefinition.RULE_REPO_KEY_SCALA;
case LicenseCheckRulesDefinition.LANG_KOTLIN:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package at.porscheinformatik.sonarqube.licensecheck.nugetlicense;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.Set;

import javax.json.Json;
import javax.json.JsonArray;
import javax.json.JsonObject;
import javax.json.JsonReader;

import org.sonar.api.batch.fs.FilePredicate;
import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.sensor.SensorContext;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;

import at.porscheinformatik.sonarqube.licensecheck.Dependency;
import at.porscheinformatik.sonarqube.licensecheck.LicenseCheckRulesDefinition;
import at.porscheinformatik.sonarqube.licensecheck.Scanner;
import at.porscheinformatik.sonarqube.licensecheck.licensemapping.LicenseMappingService;

public class NugetLicenseDependencyScanner implements Scanner
{
private static final Logger LOGGER = Loggers.get(NugetLicenseDependencyScanner.class);

private final LicenseMappingService licenseMappingService;

public NugetLicenseDependencyScanner(LicenseMappingService licenseMappingService)
{
this.licenseMappingService = licenseMappingService;
}

@Override
public Set<Dependency> scan(SensorContext context)
{
LOGGER.debug("Finding and scanning licenses.json");

FileSystem fs = context.fileSystem();
FilePredicate licenseJsonPredicate = fs.predicates().matchesPathPattern("**/licenses.json");

Set<Dependency> allDependencies = new HashSet<>();

for (InputFile licenseJsonFile : fs.inputFiles(licenseJsonPredicate))
{
context.markForPublishing(licenseJsonFile);
LOGGER.info("Scanning for licenses (file={})", licenseJsonFile.toString());
allDependencies.addAll(dependencyParser(licenseJsonFile));
}

LOGGER.debug("Nuget scanning complete.");

return allDependencies;
}

private Set<Dependency> dependencyParser(InputFile licenseJsonFile)
{
Set<Dependency> dependencies = new HashSet<>();

try (InputStream fis = licenseJsonFile.inputStream();
JsonReader jsonReader = Json.createReader(fis))
{
JsonArray licensesJson = jsonReader.readArray();

if (licensesJson != null)
{
for (int i = 0; i < licensesJson.size(); i++)
{
JsonObject nextPackage = licensesJson.getJsonObject(i);
String packageName = nextPackage.getString("PackageName");
String packageVersion = nextPackage.getString("PackageVersion");
String packageLicense = nextPackage.getString("LicenseType");

if (dependencies.stream().anyMatch(d -> packageName.equals(d.getName()) && packageVersion.equals(d.getVersion())))
{
LOGGER.debug("Package {} {} has already been encountered and will not be scanned again", packageName, packageVersion);
continue;
}

String license = licenseMappingService.mapLicense(packageLicense);

LOGGER.debug("Found license. Name: {} Version: {} License: {}", packageName, packageVersion, packageLicense);

Dependency dependency = new Dependency(packageName, packageVersion, license, LicenseCheckRulesDefinition.LANG_CS);
dependency.setInputComponent(licenseJsonFile);
dependency.setTextRange(licenseJsonFile.selectLine(1));

dependencies.add(dependency);
}
}
}
catch (IOException e)
{
LOGGER.error("Error reading license.json", e);
}

return dependencies;
}
}
2 changes: 1 addition & 1 deletion src/main/web/dashboard/dependencies.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<h3>Dependencies</h3>
<table class="data zebra">
<caption>
Here you see all project dependencies from Maven (including transitive) and NPM.
Here you see all project dependencies from Maven (including transitive), NPM and NuGet.
</caption>
<thead>
<tr>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public void define() {

new LicenseCheckRulesDefinition().define(context);

assertThat(context.repositories().size(), is(6));
assertThat(context.repositories().size(), is(7));
for (RulesDefinition.Repository repository : context.repositories()) {
assertThat(repository.rules().size(), is(2));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package at.porscheinformatik.sonarqube.licensecheck.nugetlicense;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.hasSize;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Set;

import org.junit.Test;
import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultFileSystem;
import org.sonar.api.batch.sensor.SensorContext;

import at.porscheinformatik.sonarqube.licensecheck.Dependency;
import at.porscheinformatik.sonarqube.licensecheck.Scanner;
import at.porscheinformatik.sonarqube.licensecheck.licensemapping.LicenseMappingService;

public class NugetLicenseDependencyScannerTest
{
private static final File RESOURCE_FOLDER = new File("src/test/resources");

private SensorContext createContext(File folder)
{
SensorContext context = mock(SensorContext.class);
InputFile packageJson = mock(InputFile.class);
when(packageJson.language()).thenReturn("json");
when(packageJson.filename()).thenReturn("licenses.json");
when(packageJson.relativePath()).thenReturn("/licenses.json");
when(packageJson.type()).thenReturn(InputFile.Type.MAIN);
try
{
when(packageJson.inputStream()).thenAnswer(i -> new FileInputStream(new File(folder, "licenses.json")));
}
catch (IOException e)
{
throw new RuntimeException(e);
}
FileSystem fileSystem = new DefaultFileSystem(folder.toPath()).add(packageJson);
when(context.fileSystem()).thenReturn(fileSystem);
return context;
}

@Test
public void testHappyPath()
{
Set<Dependency> dependencies = createScanner().scan(createContext(RESOURCE_FOLDER));

assertThat(dependencies, hasSize(4));
assertThat(dependencies, containsInAnyOrder(
new Dependency("MonoGame.Content.Builder.Task", "3.8.0.1641", "MS-PL"),
new Dependency("MonoGame.Framework.DesktopGL", "3.8.0.1641", "MS-PL"),
new Dependency("CommandLineParser", "2.8.0", "License.md"),
new Dependency("Newtonsoft.Json", "13.0.1", "MIT")));
}

@Test
public void testNoPackageJson()
{
Set<Dependency> dependencies = createScanner().scan(createContext(new File("src")));

assertThat(dependencies, hasSize(0));
}

private Scanner createScanner()
{
LicenseMappingService licenseMappingService = mock(LicenseMappingService.class);
when(licenseMappingService.mapLicense(anyString())).thenCallRealMethod();

return new NugetLicenseDependencyScanner(licenseMappingService);
}
}
63 changes: 63 additions & 0 deletions src/test/resources/licenses.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
[
{
"PackageName": "MonoGame.Content.Builder.Task",
"PackageVersion": "3.8.0.1641",
"PackageUrl": "https://www.monogame.net/",
"Copyright": "",
"Authors": [
"MonoGame Team"
],
"Description": "MSBuild task to automatically build content for MonoGame.",
"LicenseUrl": "https://licenses.nuget.org/MS-PL",
"LicenseType": "MS-PL",
"Repository": {
"Type": "",
"Url": "https://github.com/MonoGame/MonoGame",
"Commit": ""
}
},
{
"PackageName": "MonoGame.Framework.DesktopGL",
"PackageVersion": "3.8.0.1641",
"PackageUrl": "https://www.monogame.net/",
"Copyright": "",
"Authors": [
"MonoGame Team"
],
"Description": "The MonoGame runtime supporting Windows, Linux and macOS using SDL2 and OpenGL.",
"LicenseUrl": "https://licenses.nuget.org/MS-PL",
"LicenseType": "MS-PL",
"Repository": {
"Type": "",
"Url": "https://github.com/MonoGame/MonoGame",
"Commit": ""
}
},
{
"PackageName": "CommandLineParser",
"PackageVersion": "2.8.0",
"PackageUrl": "https://github.com/commandlineparser/commandline",
"Copyright": "Copyright (c) 2005 - 2020 Giacomo Stelluti Scala & Contributors",
"Authors": [
"gsscoder",
"nemec",
"ericnewton76",
"moh-hassan"
],
"Description": "Terse syntax C# command line parser for .NET. For FSharp support see CommandLineParser.FSharp. The Command Line Parser Library offers to CLR applications a clean and concise API for manipulating command line arguments and related tasks.",
"LicenseUrl": "https://www.nuget.org/packages/CommandLineParser/2.8.0/License",
"LicenseType": "License.md"
},
{
"PackageName": "Newtonsoft.Json",
"PackageVersion": "13.0.1",
"PackageUrl": "https://www.newtonsoft.com/json",
"Copyright": "Copyright © James Newton-King 2008",
"Authors": [
"James Newton-King"
],
"Description": "Json.NET is a popular high-performance JSON framework for .NET",
"LicenseUrl": "https://licenses.nuget.org/MIT",
"LicenseType": "MIT"
}
]