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

Feature/GitHub actions #1

Merged
merged 7 commits into from
Oct 15, 2023
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
55 changes: 55 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
name: Build

on: # yamllint disable-line rule:truthy
push:
branches:
- "master"
- "main"
- "develop"
paths-ignore:
- '.gitignore'
- 'CODEOWNERS'
- 'LICENSE'
- '*.md'
- '*.adoc'
- '*.txt'
- '.all-contributorsrc'
pull_request:
paths-ignore:
- '.gitignore'
- 'CODEOWNERS'
- 'LICENSE'
- '*.md'
- '*.adoc'
- '*.txt'
- '.all-contributorsrc'

jobs:
build:
permissions:
checks: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '17'
cache: 'gradle'
- name: Cache SonarQube packages
uses: actions/cache@v1
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar
- name: Build and analyze
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: ./gradlew build sonar --no-daemon
- name: Build native
run: ./gradlew build --no-daemon -Dquarkus.package.type=native
42 changes: 42 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
name: release-build

on: # yamllint disable-line rule:truthy
release:
types: [created]

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Install graalvm
uses: DeLaGuardo/setup-graalvm@3
with:
graalvm-version: '20.0.0.java11'
- name: Install native-image
run: gu install native-image
- name: Build native executable
run: "./gradlew -Pversion=\"${{ github.event.release.tag_name }}\" build -Dquarkus.package.type=native"
- name: Upload native executable
id: upload-native-executable
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ github.event.release.upload_url }}
asset_path: ./build/qualityannotate-${{ github.event.release.tag_name }}-runner
asset_name: qualityannotate-${{ github.event.release.tag_name }}-linux
asset_content_type: application/octet-stream
- name: Upload config
id: upload-config
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ github.event.release.upload_url }}
asset_path: ./build/resources/main/application.yml
asset_name: application.yml
asset_content_type: text/yaml
7 changes: 7 additions & 0 deletions .yamllint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
extends: default

rules:
line-length:
max: 120
level: warning
37 changes: 30 additions & 7 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
plugins {
id 'java'
id "jacoco"
id 'io.quarkus'
id("io.freefair.lombok") version "8.4"
id "org.sonarqube" version "4.3.1.3277"
}

repositories {
Expand All @@ -24,18 +26,39 @@ group 'org.acme'
version '1.0.0-SNAPSHOT'

java {
sourceCompatibility = JavaVersion.VERSION_16
targetCompatibility = JavaVersion.VERSION_16
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
compileJava {
options.encoding = 'UTF-8'
options.compilerArgs << '-parameters'
}

compileTestJava {
options.encoding = 'UTF-8'
}
}

test {
systemProperty "java.util.logging.manager", "org.jboss.logmanager.LogManager"
}
compileJava {
options.encoding = 'UTF-8'
options.compilerArgs << '-parameters'

project.tasks["sonar"].dependsOn "build"

sonar {
properties {
property "sonar.projectKey", "quyt_qualityannotate"
property "sonar.organization", "quyt"
property "sonar.host.url", "https://sonarcloud.io"

property "sonar.projectName", "Quality Annotate"
property "sonar.sourceEncoding", "UTF-8"
}
}

compileTestJava {
options.encoding = 'UTF-8'
jacocoTestReport {
reports {
xml.required = true
html.outputLocation = layout.buildDirectory.dir('jacocoHtml')
}
}
test.finalizedBy jacocoTestReport
Binary file added gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
5 changes: 5 additions & 0 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
10 changes: 10 additions & 0 deletions sonar-project.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
sonar.host.url=https://sonarcloud.io
sonar.projectName=Quality Annotate
sonar.projectKey=qualityannotate
sonar.sourceEncoding=UTF-8


sonar.sources=src/main/java/
sonar.java.libraries=target/*.jar
sonar.java.binaries=target/classes/org/acme/rest/json
sonar.java.test.binaries=target/test-classes/org/acme/rest/json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.qualityannotate.api.qualitytool;

public record Issue(String fileName, String lineNumber, String comment, String severity) {
public record Issue(String fileName, Integer lineNumber, String comment, String severity) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import io.smallrye.config.ConfigMapping;
import io.smallrye.config.WithName;

import java.util.List;

@ConfigMapping(prefix = "sonarqube")
public interface SonarqubeConfig {
@WithName("url")
Expand All @@ -16,4 +18,7 @@ public interface SonarqubeConfig {

@WithName("pull_request")
String pullRequest();

@WithName("global_metric_types")
List<String> globalMetricTypes();
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.qualityannotate.core.rest.BasicAuthRequestFilter;
import org.qualityannotate.quality.sonarqube.client.ComponentMeasures;
import org.qualityannotate.quality.sonarqube.client.Measure;
import org.qualityannotate.quality.sonarqube.client.Metric;
import org.qualityannotate.quality.sonarqube.client.SonarqubeApiClient;
import org.qualityannotate.quality.sonarqube.client.*;
import org.qualityannotate.api.qualitytool.GlobalMetrics;
import org.qualityannotate.api.qualitytool.Issue;
import org.qualityannotate.api.qualitytool.QualityTool;
Expand All @@ -31,16 +28,34 @@ public SonarqubeQualityTool(SonarqubeConfig config) {

@Override
public List<Issue> getIssues() {
return Collections.emptyList();
IssueSearch issuesSearch = client.getIssuesSearch(config.project(), config.pullRequest(), null, null, null, null, null, null, null, null, null);
// TODO issueSearch.facets can be used for globalMetrics - but maybe doesn't matter
List<Issue> issues = new ArrayList<>();
for (SqIssue sqIssue : issuesSearch.issues()) {
issues.add(new Issue(sqIssue.getPath(config.project()), sqIssue.getLineNumber(), sqIssue.getMessage(), sqIssue.getSeverity()));
}
return issues;
}

@Override
public GlobalMetrics getGlobalMetrics() {
ComponentMeasures componentMeasures = client.getComponentMeasures(config.project(), config.pullRequest(), "new_coverage,new_sqale_debt_ratio,new_uncovered_conditions");
ComponentMeasures componentMeasures = client.getComponentMeasures(config.project(), config.pullRequest(),
String.join(",", config.globalMetricTypes()));
Map<String, String> metrics = new HashMap<>();
for (Metric metric : componentMeasures.getMetrics()) {
Optional<Measure> measure = componentMeasures.getComponent().getMeasure(metric.getKey());
measure.ifPresent(value -> metrics.put(metric.getName(), value.getPeriod() == null ? value.getValue() : value.getPeriod().value()));
Optional<Measure> measureOpt = componentMeasures.getComponent().getMeasure(metric.getKey());
if (measureOpt.isPresent()) {
Measure measure = measureOpt.get();
String value = measure.getPeriod() == null ? measure.getValue() : measure.getPeriod().value();
if (metric.getKey().endsWith("coverage")) {
try {
value = String.format("%.2f%%", Double.parseDouble(value));
} catch (NumberFormatException e) {
// ignore
}
}
metrics.put(metric.getName(), value);
}
}
return new GlobalMetrics(metrics);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
package org.qualityannotate.quality.sonarqube.client;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Value;

import java.util.List;
import java.util.Optional;

@Value
@JsonIgnoreProperties(ignoreUnknown = true)
public class Component {
/**
* "key": "MY_PROJECT:ElementImpl.java",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
package org.qualityannotate.quality.sonarqube.client;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

import java.util.List;

@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class ComponentMeasures {
@JsonProperty("component")
public Component component;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.qualityannotate.quality.sonarqube.client;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

import java.util.List;

public record Facet(List<FacetValue> values) {

/**
* @param val human readable name of the Facet
* @param count some metric count
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public record FacetValue(String val, String count) {

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.qualityannotate.quality.sonarqube.client;

import java.util.List;

public record IssueSearch(Paging paging, List<SqIssue> issues, List<Component> components, List<Facet> facets) {
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
package org.qualityannotate.quality.sonarqube.client;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Value;

@Value
@JsonIgnoreProperties(ignoreUnknown = true)
public class Measure {
/**
* "metric": "complexity",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.qualityannotate.quality.sonarqube.client;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown = true)
public record Paging(int pageIndex, int pageSize, int total) {
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package org.qualityannotate.quality.sonarqube.client;


import jakarta.annotation.Nullable;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.QueryParam;
Expand All @@ -10,15 +12,48 @@
@Path("/api")
public interface SonarqubeApiClient {
/**
* <a href="https://sonarqube.inria.fr/sonarqube/web_api/api/measures?internal=true">docs</a>
* <a href="https://sonarqube.inria.fr/sonarqube/web_api/api/measures">docs</a>
*
* @param project Component key. E.g. my_project
* @param prId Pull request id. Not available in the community edition. E.g. 1234
* @param metricKeys Comma-separated list of additional fields that can be returned in the response.
* E.g."new_coverage,new_sqale_debt_ratio,new_uncovered_conditions"
* @return
*/
@GET()
@Path("/measures/component")
ComponentMeasures getComponentMeasures(@QueryParam("component") String project, @QueryParam("pullRequest") String prId, @QueryParam("metricsKeys") String metricKeys);


/**
* <a href="https://sonarqube.inria.fr/sonarqube/web_api/api/issues/search">docs</a>
* TODO onComponentOnly might be interesting to retrieve global metrics
*
* @param project Component key. E.g. my_project
* @param prId Pull request id. Not available in the community edition. E.g. 1234
* @param branch BBranch key. Not available in the community edition. E.g. feature/test
* @param additionalFields Comma-separated list of the optional fields to be returned in response.
* @param facets Comma-separated list of the facets to be computed. No facet is computed by default.
* @param pageNumber Page number. E.g. 1
* @param pageSize Page size. Highest number is 500
* @param resolved To match resolved or unresolved issues
* @param sort Sort the issues
* @param severities Comma-separated list of severities
* @param statuses Comma-separated list of statuses
*/
@GET()
@Path("/issues/search")
IssueSearch getIssuesSearch(@QueryParam("componentKeys") String project,
@Nullable @QueryParam("pullRequest") String prId,
@Nullable @QueryParam("branch") String branch,
@Nullable @QueryParam("additionalFields") @DefaultValue("_all") String additionalFields,
@Nullable @QueryParam("facets") @DefaultValue("severities,types") String facets,
@Nullable @QueryParam("p") @DefaultValue("1") String pageNumber,
// 500 is the biggest size
@Nullable @QueryParam("ps") @DefaultValue("500") String pageSize,
@Nullable @QueryParam("resolved") @DefaultValue("false") String resolved,
@Nullable @QueryParam("s") @DefaultValue("FILE_LINE") String sort,
// INFO got removed here
@Nullable @QueryParam("severities") @DefaultValue("MINOR,MAJOR,CRITICAL,BLOCKER") String severities,
@Nullable @QueryParam("statuses") @DefaultValue("OPEN,REOPENED,CONFIRMED") String statuses
);
}
Loading
Loading