Implemented update check.

Implemented settings properties and parameters.
Implemented logging.
This commit is contained in:
Erik C. Thauvin 2016-07-30 19:46:42 -07:00
parent 5c41c4489c
commit 6e26a1bd68

View file

@ -36,6 +36,7 @@ import com.beust.kobalt.TaskResult
import com.beust.kobalt.api.* import com.beust.kobalt.api.*
import com.beust.kobalt.api.annotation.Directive import com.beust.kobalt.api.annotation.Directive
import com.beust.kobalt.api.annotation.Task import com.beust.kobalt.api.annotation.Task
import com.beust.kobalt.misc.KobaltLogger
import com.beust.kobalt.misc.log import com.beust.kobalt.misc.log
import com.beust.kobalt.misc.warn import com.beust.kobalt.misc.warn
import com.google.gson.GsonBuilder import com.google.gson.GsonBuilder
@ -43,7 +44,6 @@ import com.google.gson.JsonObject
import com.google.inject.Inject import com.google.inject.Inject
import com.google.inject.Singleton import com.google.inject.Singleton
import okhttp3.* import okhttp3.*
import java.io.File
import java.io.FileOutputStream import java.io.FileOutputStream
import java.nio.file.Files import java.nio.file.Files
import java.nio.file.Paths import java.nio.file.Paths
@ -55,8 +55,11 @@ class VersionEyePlugin @Inject constructor(val configActor: ConfigActor<VersionE
BasePlugin(), ITaskContributor, IConfigActor<VersionEyeConfig> by configActor { BasePlugin(), ITaskContributor, IConfigActor<VersionEyeConfig> by configActor {
private val API_KEY_PROPERTY = "versioneye.apiKey" private val API_KEY_PROPERTY = "versioneye.apiKey"
private val PROJECT_KEY_PROPERTY = "versioneye.projectKey" private val PROJECT_KEY_PROPERTY = "versioneye.projectKey"
private val COLORS_PROPERTY = "ve.colors"
private val VERBOSE_PROPERTY = "ve.verbose"
private val QUIET_PROPERTY = "ve.quiet"
private val debug = System.getProperty("debug", "false").toBoolean() private val debug = System.getProperty("ve.debug", "false").toBoolean()
private val httpClient = OkHttpClient() private val httpClient = OkHttpClient()
// ITaskContributor // ITaskContributor
@ -86,11 +89,13 @@ class VersionEyePlugin @Inject constructor(val configActor: ConfigActor<VersionE
val local = project.directory + "/local.properties" val local = project.directory + "/local.properties"
// Load configuration
configurationFor(project)?.let { config -> configurationFor(project)?.let { config ->
if (config.baseUrl.isBlank()) { if (config.baseUrl.isBlank()) {
warn("Please specify a valid VersionEye base URL.") warn("Please specify a valid VersionEye base URL.")
return TaskResult() return TaskResult()
} else { } else {
// Load properties
val projectKey = System.getProperty(PROJECT_KEY_PROPERTY) val projectKey = System.getProperty(PROJECT_KEY_PROPERTY)
var apiKey = System.getProperty(API_KEY_PROPERTY) var apiKey = System.getProperty(API_KEY_PROPERTY)
val p = Properties() val p = Properties()
@ -102,7 +107,7 @@ class VersionEyePlugin @Inject constructor(val configActor: ConfigActor<VersionE
} }
} }
// API key?
if (apiKey.isNullOrBlank()) { if (apiKey.isNullOrBlank()) {
apiKey = p.getProperty(API_KEY_PROPERTY) apiKey = p.getProperty(API_KEY_PROPERTY)
if (apiKey.isNullOrBlank()) { if (apiKey.isNullOrBlank()) {
@ -112,16 +117,25 @@ class VersionEyePlugin @Inject constructor(val configActor: ConfigActor<VersionE
} }
p.setProperty(API_KEY_PROPERTY, apiKey) p.setProperty(API_KEY_PROPERTY, apiKey)
// Project key?
if (!projectKey.isNullOrBlank()) { if (!projectKey.isNullOrBlank()) {
p.setProperty(PROJECT_KEY_PROPERTY, projectKey) p.setProperty(PROJECT_KEY_PROPERTY, projectKey)
} }
// Config parameters
config.colors = System.getProperty(COLORS_PROPERTY, config.colors.toString()).toBoolean()
config.verbose = System.getProperty(VERBOSE_PROPERTY, config.verbose.toString()).toBoolean()
config.quiet = System.getProperty(QUIET_PROPERTY, config.quiet.toString()).toBoolean()
// Get pom & proceed with update
val pom = context.generatePom(project)
val result = versionEyeUpdate(if (config.name.isNotBlank()) { val result = versionEyeUpdate(if (config.name.isNotBlank()) {
config.name config.name
} else { } else {
project.name project.name
}, config, p) }, config, p, pom)
// Save properties
FileOutputStream(local).use { output -> FileOutputStream(local).use { output ->
p.store(output, "") p.store(output, "")
} }
@ -132,28 +146,36 @@ class VersionEyePlugin @Inject constructor(val configActor: ConfigActor<VersionE
return TaskResult() return TaskResult()
} }
private fun versionEyeUpdate(name: String, config: VersionEyeConfig, p: Properties): TaskResult { private fun versionEyeUpdate(name: String, config: VersionEyeConfig, p: Properties, pom: String): TaskResult {
val projectKey = p.getProperty(PROJECT_KEY_PROPERTY) val projectKey = p.getProperty(PROJECT_KEY_PROPERTY)
val apiKey = p.getProperty(API_KEY_PROPERTY) val apiKey = p.getProperty(API_KEY_PROPERTY)
val endPoint = if (projectKey.isNullOrBlank()) { val filePartName: String
"api/v2/projects" val endPoint: String
// Set endpoint
if (projectKey.isNullOrBlank()) {
endPoint = "api/v2/projects"
filePartName = "upload"
} else { } else {
"api/v2/project/$projectKey" endPoint = "api/v2/projects/$projectKey"
filePartName = "project_file"
} }
val file = File("../kobaltBuild/libs/kobalt-versioneye-0.4.0-beta.pom") // Build request body
val requestBody = MultipartBody.Builder() val requestBody = MultipartBody.Builder()
.setType(MultipartBody.FORM) .setType(MultipartBody.FORM)
.addFormDataPart("name", name) .addFormDataPart("name", name)
.addFormDataPart("upload", file.name, .addFormDataPart(filePartName, "${config.name}.pom",
RequestBody.create(MediaType.parse("application/octet-stream"), file)) RequestBody.create(MediaType.parse("application/octet-stream"), pom))
// Set organisation
val hasOrg = config.org.isNotBlank() val hasOrg = config.org.isNotBlank()
if (hasOrg) { if (hasOrg) {
requestBody.addFormDataPart("orga_name", config.org) requestBody.addFormDataPart("orga_name", config.org)
} }
// Set team
if (config.team.isNotBlank()) { if (config.team.isNotBlank()) {
if (hasOrg) { if (hasOrg) {
requestBody.addFormDataPart("team_name", config.team) requestBody.addFormDataPart("team_name", config.team)
@ -162,10 +184,20 @@ class VersionEyePlugin @Inject constructor(val configActor: ConfigActor<VersionE
} }
} }
// Set visibility
if (config.visibility.isNotBlank()) {
if (config.visibility.equals("private", true)) {
requestBody.addFormDataPart("visibility", "private")
} else if (config.visibility.equals("public", true)) {
requestBody.addFormDataPart("visibility", "public")
}
}
if (debug) { if (debug) {
requestBody.addFormDataPart("temp", "true") requestBody.addFormDataPart("temp", "true")
} }
// Build request
val url = HttpUrl.parse(config.baseUrl).newBuilder() val url = HttpUrl.parse(config.baseUrl).newBuilder()
.addPathSegments(endPoint) .addPathSegments(endPoint)
.setQueryParameter("api_key", apiKey) .setQueryParameter("api_key", apiKey)
@ -175,29 +207,177 @@ class VersionEyePlugin @Inject constructor(val configActor: ConfigActor<VersionE
.post(requestBody.build()) .post(requestBody.build())
.build() .build()
// Execute and handle request
val response = httpClient.newCall(request).execute() val response = httpClient.newCall(request).execute()
if (!response.isSuccessful) { if (!response.isSuccessful) {
warn("Unexpected response from VersionEye: " + response) warn("Unexpected response from VersionEye: " + response)
return TaskResult() return TaskResult()
} else { } else {
// Parse json response
val builder = GsonBuilder() val builder = GsonBuilder()
val o = builder.create().fromJson(response.body().charStream(), JsonObject::class.java) val o = builder.create().fromJson(response.body().charStream(), JsonObject::class.java)
println(o)
// Get project key
if (projectKey.isNullOrBlank()) {
p.setProperty(PROJECT_KEY_PROPERTY, o.get("id").asString)
}
// Get deps, license and security counts
val dep_number = o.get("dep_number").asInt
val out_number = o.get("out_number").asInt
val licenses_red = o.get("licenses_red").asInt
val licenses_unknown = o.get("licenses_unknown").asInt
val sv_count = o.get("sv_count").asInt
// Sets deps, license and security failures
val isFailDeps = Utils.isFail(config.failSet, Fail.dependenciesCheck)
val isFailLicense = Utils.isFail(config.failSet, Fail.licensesCheck)
val isFailUnknown = Utils.isFail(config.failSet, Fail.licensesUnknownCheck)
val isFailSecurity = Utils.isFail(config.failSet, Fail.securityCheck)
// Do nothing if quiet
if (!config.quiet) {
val lf = System.getProperty("line.separator")
val depsInfo = StringBuilder()
val licensesInfo = StringBuilder()
val securityInfo = StringBuilder()
// Parse dependencies
o.getAsJsonArray("dependencies").forEach {
val dep = it.asJsonObject
val depName = dep.get("name").asString
val curVer = dep.get("version_current").asString
// Outdated dependencies
if (dep.get("outdated").asBoolean) {
if (depsInfo.isNotEmpty()) {
depsInfo.append(lf)
}
depsInfo.append(Utils.redLight(" - $depName -> $curVer", out_number, isFailDeps,
config.colors))
}
// Parse licenses
var whitelisted: Int = 0
var unknowns: Int = 0
val licenses = dep.get("licenses").asJsonArray
if (licenses.size() > 0) {
licenses.forEach {
val license = it.asJsonObject
val onWhitelist = license.get("on_whitelist")
val onCwl = license.get("on_cwl")
if (!onWhitelist.isJsonNull) {
if (onWhitelist.asString.equals("false")) {
if (onCwl.isJsonNull) {
whitelisted++
} else if (!onCwl.toString().equals("true")) {
whitelisted++
}
}
}
}
} else {
unknowns++
}
// Whitelisted
if (whitelisted > 0) {
if (licensesInfo.isNotEmpty()) {
licensesInfo.append(lf)
}
licensesInfo.append(Utils.redLight(" - $depName: $whitelisted whitelist "
+ Utils.plural("violation", whitelisted, "s"), whitelisted, isFailLicense, config.colors))
}
// Unknowns
if (unknowns > 0) {
if (licensesInfo.isNotEmpty()) {
licensesInfo.append(lf)
}
licensesInfo.append(Utils.redLight(" - $depName: $unknowns "
+ Utils.plural("unknown license", unknowns, "s"), unknowns, isFailUnknown, config.colors))
}
// Security vulnerabilities
val security = dep.get("security_vulnerabilities")
if (!security.isJsonNull) {
if (securityInfo.length > 0) {
securityInfo.append(lf)
}
val count = security.asJsonArray.size()
securityInfo.append(Utils.redLight(" - $depName: $count "
+ Utils.plural("known issue", count, "s"), count, isFailSecurity, config.colors))
}
}
// Non-verbose failure
val verbose = (KobaltLogger.LOG_LEVEL > 1 || config.verbose)
val alt = " [FAILED]"
// Log dependencies check results
log(1, " Dependencies: "
+ Utils.redLight(out_number, isFailDeps, config.colors) + " outdated of $dep_number total"
+ if (isFailDeps && !config.colors) alt else "")
Utils.log(depsInfo, verbose)
// Log licenses check results
log(1, " Licenses: "
+ Utils.redLight(licenses_red, isFailLicense, config.colors)
+ " whitelist, "
+ Utils.redLight(licenses_unknown, isFailUnknown, config.colors)
+ Utils.plural(" unknown", licenses_unknown, "s")
+ if ((isFailLicense || isFailUnknown) && !config.colors) alt else "")
Utils.log(licensesInfo, verbose)
// Log security check results
log(1, " Security: "
+ Utils.redLight(sv_count, isFailSecurity, config.colors)
+ ' '
+ Utils.plural("vulnerabilit", sv_count, "ies", "y")
+ if (isFailSecurity && !config.colors) alt else "")
Utils.log(securityInfo, verbose)
}
// Show project url
if (!config.quiet) {
val baseUrl = if (config.baseUrl.endsWith('/')) config.baseUrl else config.baseUrl + '/'
log(1, " View more at: ${baseUrl}user/projects/$projectKey")
}
// Task failure
if (out_number > 0 && isFailDeps
|| licenses_red > 0 && isFailLicense
|| licenses_unknown > 0 && isFailUnknown
|| sv_count > 0 && isFailSecurity) {
return TaskResult(false)
}
} }
return TaskResult() return TaskResult()
} }
} }
enum class Fail {
dependenciesCheck, licensesUnknownCheck, licensesCheck, securityCheck
}
@Directive @Directive
class VersionEyeConfig() { class VersionEyeConfig() {
var baseUrl = "https://www.versioneye.com/" var baseUrl = "https://www.versioneye.com/"
var failOnUnknownLicense = false var colors = true
var licenseCheck = false var failSet: MutableSet<Fail> = mutableSetOf()
var name = "" var name = ""
var org = "" var org = ""
var securityCheck = false var quiet = false
var team = "" var team = ""
var visibility = true var verbose = true
var visibility = "public"
fun failOn(vararg args: Fail) {
args.forEach {
failSet.add(it)
}
}
} }
@Directive @Directive