Skip to content

Commit

Permalink
✨ provide ios support
Browse files Browse the repository at this point in the history
  • Loading branch information
etiennecadicidean committed Feb 10, 2022
1 parent e36dfd0 commit 39bd586
Show file tree
Hide file tree
Showing 8 changed files with 171 additions and 25 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,18 @@ Note: Please check above link for instructions or follow as mentioned below
> gradle sonarqube


### IOS (Cocoapods, Carthage & Swift Package Manager)

Use custom LicenseFinder ruby gem <http:>https://github.com/etiennecadicidean/LicenseFinder</http:> to generate license report for ios
projects

```
mkdir -p build/reports/license_finder/
license_finder report -p --format json -q > build/reports/license_finder/swift-license-details.json
```

Then run sonarqube analysis

## Features

### Analysis
Expand All @@ -118,6 +130,7 @@ Currently supported formats are:
* Maven POM files - all dependencies with scope "compile" and "runtime" are checked
* NPM package.json files - all dependencies (except "devDependencies") are checked
* Note that transitive dependencies are _not_ scanned unless `licensecheck.npm.resolvetransitive` is set to `true`.
* Swift dependencies (Reports must be generated with `License_finder tool`)

### Project Dashboard

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ public final class LicenseCheckRulesDefinition implements RulesDefinition
public static final String LANG_JS = "js";
public static final String LANG_GROOVY = "grvy";
public static final String LANG_KOTLIN = "kotlin";

public static final String LANG_SWIFT = "swift";

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_GROOVY = "licensecheck-groovy";
public static final String RULE_REPO_KEY_KOTLIN = "licensecheck-kotlin";
public static final String RULE_REPO_KEY_SWIFT = "licensecheck-swift";

public static final String RULE_UNLISTED_KEY = "licensecheck.unlisted";
public static final String RULE_NOT_ALLOWED_LICENSE_KEY = "licensecheck.notallowedlicense";
Expand All @@ -29,6 +31,7 @@ public void define(Context context)
context.createRepository(RULE_REPO_KEY_JS, LANG_JS),
context.createRepository(RULE_REPO_KEY_GROOVY, LANG_GROOVY),
context.createRepository(RULE_REPO_KEY_KOTLIN, LANG_KOTLIN),
context.createRepository(RULE_REPO_KEY_SWIFT, LANG_SWIFT),
};

for (NewRepository repo : repos)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static at.porscheinformatik.sonarqube.licensecheck.LicenseCheckRulesDefinition.RULE_REPO_KEY;
import static at.porscheinformatik.sonarqube.licensecheck.LicenseCheckRulesDefinition.RULE_REPO_KEY_GROOVY;
import static at.porscheinformatik.sonarqube.licensecheck.LicenseCheckRulesDefinition.RULE_REPO_KEY_JS;
import static at.porscheinformatik.sonarqube.licensecheck.LicenseCheckRulesDefinition.RULE_REPO_KEY_SWIFT;

import java.util.Set;
import java.util.TreeSet;
Expand All @@ -22,6 +23,7 @@
import at.porscheinformatik.sonarqube.licensecheck.licensemapping.LicenseMappingService;
import at.porscheinformatik.sonarqube.licensecheck.maven.MavenDependencyScanner;
import at.porscheinformatik.sonarqube.licensecheck.npm.PackageJsonDependencyScanner;
import at.porscheinformatik.sonarqube.licensecheck.swift.SwiftDependencyScanner;

public class LicenseCheckSensor implements Sensor
{
Expand All @@ -43,7 +45,9 @@ public LicenseCheckSensor(FileSystem fs, Configuration configuration, ValidateLi
new PackageJsonDependencyScanner(licenseMappingService,
configuration.getBoolean(LicenseCheckPropertyKeys.NPM_RESOLVE_TRANSITIVE_DEPS).orElse(false)),
new MavenDependencyScanner(licenseMappingService),
new GradleDependencyScanner(licenseMappingService)};
new GradleDependencyScanner(licenseMappingService),
new SwiftDependencyScanner(licenseMappingService),
};
}

private static void saveDependencies(SensorContext sensorContext, Set<Dependency> dependencies)
Expand Down Expand Up @@ -114,7 +118,7 @@ private static void saveMeasures(SensorContext sensorContext, Set<License> licen
public void describe(SensorDescriptor descriptor)
{
descriptor.name("License Check")
.createIssuesForRuleRepositories(RULE_REPO_KEY, RULE_REPO_KEY_JS, RULE_REPO_KEY_GROOVY);
.createIssuesForRuleRepositories(RULE_REPO_KEY, RULE_REPO_KEY_JS, RULE_REPO_KEY_GROOVY, RULE_REPO_KEY_SWIFT);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,8 @@ private static String getRepoKey(Dependency dependency)
return LicenseCheckRulesDefinition.RULE_REPO_KEY_JS;
case LicenseCheckRulesDefinition.LANG_GROOVY:
return LicenseCheckRulesDefinition.RULE_REPO_KEY_GROOVY;
case LicenseCheckRulesDefinition.LANG_SWIFT:
return LicenseCheckRulesDefinition.RULE_REPO_KEY_SWIFT;
case LicenseCheckRulesDefinition.LANG_JAVA:
default:
return LicenseCheckRulesDefinition.RULE_REPO_KEY;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
import javax.json.JsonObject;
import javax.json.JsonReader;

import org.codehaus.plexus.util.StringUtils;
import org.sonar.api.batch.sensor.SensorContext;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
Expand All @@ -25,6 +24,7 @@
import at.porscheinformatik.sonarqube.licensecheck.LicenseCheckRulesDefinition;
import at.porscheinformatik.sonarqube.licensecheck.Scanner;
import at.porscheinformatik.sonarqube.licensecheck.licensemapping.LicenseMappingService;
import at.porscheinformatik.sonarqube.licensecheck.utils.LicenseUtils;

public class GradleDependencyScanner implements Scanner
{
Expand Down Expand Up @@ -56,7 +56,7 @@ public Set<Dependency> scan(SensorContext context)

return readLicenseDetailsJson(licenseDetailsJsonFile)
.stream()
.map(d -> matchLicense(defaultLicenseMap, d))
.map(d -> LicenseUtils.matchLicense(defaultLicenseMap, d))
.peek(d -> d.setInputComponent(context.module()))
.collect(Collectors.toSet());
}
Expand Down Expand Up @@ -123,23 +123,4 @@ private String getModuleLicense(JsonArray arrModuleLicenses)
}
return moduleLicense;
}

private Dependency matchLicense(Map<Pattern, String> licenseMap, Dependency dependency)
{
if (StringUtils.isBlank(dependency.getLicense()))
{
LOGGER.info("Dependency '{}' has no license set.", dependency.getName());
return dependency;
}

for (Map.Entry<Pattern, String> entry : licenseMap.entrySet())
{
if (entry.getKey().matcher(dependency.getLicense()).matches())
{
dependency.setLicense(entry.getValue());
break;
}
}
return dependency;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package at.porscheinformatik.sonarqube.licensecheck.swift;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

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

import org.codehaus.plexus.util.StringUtils;
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;
import at.porscheinformatik.sonarqube.licensecheck.utils.LicenseUtils;

/*
* This Swift dependency scanner is based on reports produced by LicenseFinder opensource tool
*/
public class SwiftDependencyScanner implements Scanner {
private static final Logger LOGGER = Loggers.get(SwiftDependencyScanner.class);
private final LicenseMappingService licenseMappingService;

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

@Override
public Set<Dependency> scan(SensorContext context) {
File moduleDir = context.fileSystem().baseDir();

Map<Pattern, String> defaultLicenseMap = licenseMappingService.getLicenseMap();

File licenseDetailsJsonFile = new File(moduleDir, "build" + File.separator + "reports" + File.separator
+ "license_finder" + File.separator + "swift-license-details.json");

if (!licenseDetailsJsonFile.exists()) {
LOGGER.info("No license-details.json file found in {} - skipping Swift dependency scan",
licenseDetailsJsonFile.getPath());
return Collections.emptySet();
}

return readLicenseDetailsJson(licenseDetailsJsonFile)
.stream()
.map(d -> LicenseUtils.matchLicense(defaultLicenseMap, d))
.peek(d -> d.setInputComponent(context.module()))
.collect(Collectors.toSet());
}

private Set<Dependency> readLicenseDetailsJson(File licenseDetailsJsonFile) {
final Set<Dependency> dependencySet = new HashSet<>();

try (InputStream fis = new FileInputStream(licenseDetailsJsonFile);
JsonReader jsonReader = Json.createReader(fis)) {
JsonObject jo = jsonReader.readObject();
JsonArray arr = jo.getJsonArray("dependencies");
prepareDependencySet(dependencySet, arr);
return dependencySet;
} catch (Exception e) {
LOGGER.error("Problems reading Swift license file {}: {}",
licenseDetailsJsonFile.getPath(), e.getMessage());
}
return dependencySet;
}

private void prepareDependencySet(Set<Dependency> dependencySet, JsonArray arr) {
for (javax.json.JsonValue entry : arr) {
JsonObject jsonDepObj = entry.asJsonObject();
String moduleLicense = getModuleLicenseFromJsonObject(jsonDepObj);
String moduleLicenseUrl = null;

Dependency dep = new Dependency(jsonDepObj.getString("name", null),
jsonDepObj.getString("version", null), moduleLicense, LicenseCheckRulesDefinition.LANG_SWIFT);
dep.setPomPath(moduleLicenseUrl);
dependencySet.add(dep);
}
}

private String getModuleLicenseFromJsonObject(JsonObject jsonDepObj) {
String moduleLicense = null;
JsonArray arrModuleLicenses = jsonDepObj.getJsonArray("licenses");
if (arrModuleLicenses != null) {
moduleLicense = getModuleLicense(arrModuleLicenses);
}
return moduleLicense;
}

private String getModuleLicense(JsonArray arrModuleLicenses) {
if (arrModuleLicenses != null && !arrModuleLicenses.isEmpty()) {
if (arrModuleLicenses.getString(0).equals("unknown"))
return null;
return arrModuleLicenses.getString(0);
} else {
return null;
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package at.porscheinformatik.sonarqube.licensecheck.utils;

import java.util.Map;
import java.util.regex.Pattern;

import org.sonar.api.internal.apachecommons.lang.StringUtils;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;

import at.porscheinformatik.sonarqube.licensecheck.Dependency;

public class LicenseUtils {

private LicenseUtils() {}

private static final Logger LOGGER = Loggers.get(LicenseUtils.class);

static public Dependency matchLicense(Map<Pattern, String> licenseMap, Dependency dependency) {
if (StringUtils.isBlank(dependency.getLicense())) {
LOGGER.info("Dependency '{}' has no license set.", dependency.getName());
return dependency;
}

for (Map.Entry<Pattern, String> entry : licenseMap.entrySet()) {
if (entry.getKey().matcher(dependency.getLicense()).matches()) {
dependency.setLicense(entry.getValue());
break;
}
}
return dependency;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public void define()

new LicenseCheckRulesDefinition().define(context);

assertThat(context.repositories().size(), is(4));
assertThat(context.repositories().size(), is(5));
for (RulesDefinition.Repository repository : context.repositories())
{
assertThat(repository.rules().size(), is(2));
Expand Down

0 comments on commit 39bd586

Please sign in to comment.