I am a software engineer. You can view my portfolio at https://jaredsburrows.com/ and email me here: [email protected].
Gradle plugin that provides a task to generate a HTML license report of your project.
Home Page: https://central.sonatype.com/artifact/com.jaredsburrows/gradle-license-plugin
License: Apache License 2.0
I am a software engineer. You can view my portfolio at https://jaredsburrows.com/ and email me here: [email protected].
Hi,
I have setup your library as instructed but when I build and run my app nothing is generated in the assets folder but when I run the task manually it runs correctly. Am I incorrect in assuming that the task will run automatically?
This is my setup:
Top level gradle file
buildscript {
ext.kotlin_version = '1.3.50'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.1'
classpath 'com.jaredsburrows:gradle-license-plugin:0.8.6'
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
app module gradle file
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
apply plugin: 'com.jaredsburrows.license'
licenseReport {
generateHtmlReport = false
generateJsonReport = true
copyJsonReportToAssets = true
}
I have added the following to the build.gradle file of one of the projects:
plugins {
id "com.jaredsburrows.license" version "0.8.42"
}
but the licenseReport task cannot be found, but while it is available when I added the plugin to a project that I downloaded from the springInitializer then it works.
Could you indicate whether this plugin should also work in a multi project?
This issue only exist for me to reference in an incoming pull request.
It would be quite useful if the plugin allows devs to define the asset folder destination and the related file name (both for the json and html).
I've been trying to set up my project so that the report generation task for the current build variant automatically runs each time the project is rebuilt, so that I can automatically copy the JSON report into the build variant's assets directory. I've managed to make the report tasks run on rebuild, but the generated reports are always empty.
Here's the root build.gradle file:
buildscript {
repositories {
google()
jcenter()
mavenCentral()
maven {
url 'https://maven.fabric.io/public'
}
maven {
url 'https://oss.sonatype.org/content/repositories/snapshots'
}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
classpath 'io.fabric.tools:gradle:1.24.5'
classpath 'com.jakewharton:butterknife-gradle-plugin:9.0.0-SNAPSHOT'
classpath 'com.jaredsburrows:gradle-license-plugin:0.7.0'
}
}
allprojects {
repositories {
google()
jcenter()
mavenCentral()
maven {
url 'https://maven.fabric.io/public'
}
maven {
url "https://jitpack.io"
}
}
}
apply from: 'dependencies.gradle'
ext.compileSdkVersion = 26
ext.minimumSdkVersion = 17
ext.targetSdkVersion = 26
ext.releaseName = '0.0.0'
ext.releaseCode = 0
ext.buildToolsVersion = '26.0.2'
ext.applicationId = 'TODO'
task clean(type: Delete) {
delete rootProject.buildDir
rootProject.getAllprojects().each {
delete project.buildDir
}
}
Here's the dependencies.gradle file it references (it's just static definitions):
ext.dependencies = [
androidSupport: [
appCompat: 'com.android.support:appcompat-v7:26.1.0',
annotations: 'com.android.support:support-annotations:26.1.0',
cardView: 'com.android.support:cardview-v7:26.1.0',
design: 'com.android.support:design:26.1.0',
]
// Trimmed for relevance
]
Here's the build.gradle file for a library subproject:
apply plugin: 'com.android.library'
apply plugin: 'com.jaredsburrows.license'
android {
buildToolsVersion rootProject.ext.buildToolsVersion
compileSdkVersion rootProject.ext.compileSdkVersion
defaultConfig {
minSdkVersion rootProject.ext.minimumSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
vectorDrawables.useSupportLibrary true
}
buildTypes {
debug {
// Some buildConfigField declarations
}
staging {
// Some buildConfigField declarations
}
release {
// Some buildConfigField declarations
}
}
}
dependencies {
implementation rootProject.ext.dependencies.androidSupport.appCompat
}
afterEvaluate {
project.android.libraryVariants.each {
final buildTypeName = it.name
final reportTask = tasks.getByName("license${buildTypeName.capitalize()}Report")
reportTask.doLast {
// HTML report is not needed
project.file('src/main/assets/open_source_licenses.html').delete()
// Remove JSON report from previous build
project.file("src/${buildTypeName}/assets/licenseReport.json").delete()
// Copy and rename current report
copy {
from 'build/reports/licenses/'
into "src/${buildTypeName}/assets/"
include "license${buildTypeName.capitalize()}Report.json"
rename { fileName ->
fileName.replace(buildTypeName.capitalize(), '')
}
}
}
tasks.getByName("assemble${buildTypeName.capitalize()}").dependsOn(reportTask)
}
}
When I use 'Build > Rebuild project' from the Android Studio toolbar, the reporting task for the current build variant runs, and the report is copied to the correct folder, but the report is empty. The JSON report for example just contains []
. I've checked the report in the build/reports/licenses
directory and it's empty too, which means my copy task is fine.
I think I'm just running the report task at the wrong time. What can be changed so that the the copied report contains the dependencies?
Hi Jared,
thanks for the plugin for really good. But one question, would it be possible that the plugin checks all dependencies transitively through the dependent subprojects? Currently, I have to duplicate all dependencies into the Android App module, otherwise, they are not recognized.
This is a reactivation of issue #50. I'm working on that now, with pretty fair progress.
Handling the many instances of incomplete information in the POM will be "interesting".
I have tried to generate reports every time the project is built, but in case I add the LicenseReport task to run before another task both the generated html and json files are empty.
As I can see in the discussion in issue #22 it should be possible since version 0.8.1.
If I run the task individually with ./gradlew licenseDebugReport
the generated files contain all the dependencies I have. However if I run the ./gradlew assembleDebug
I can see in the logs that the task was run, and it prints that the reports were generated, but they are empty.
@MatthewTamlin Can you see what the problem might be with my configuration?
log:
$ ./gradlew assembleDebug
> Task :app:licenseDebugReport
Wrote HTML report to /Users/szugyiczkicsaba/Downloads/MyApplication/app/build/reports/licenses/licenseDebugReport.html.
Wrote JSON report to /Users/szugyiczkicsaba/Downloads/MyApplication/app/build/reports/licenses/licenseDebugReport.json.
BUILD SUCCESSFUL in 1s
26 actionable tasks: 26 executed
My configuration:
Project level build.gradle
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
classpath "com.jaredsburrows:gradle-license-plugin:0.8.3"
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
App module build.gradle
apply plugin: 'com.android.application'
apply plugin: "com.jaredsburrows.license"
licenseReport {
generateHtmlReport = true
generateJsonReport = true
// These options are ignored for Java projects
copyJsonReportToAssets = true
}
android.applicationVariants.all { variant ->
def variantCapitalized = variant.name.capitalize()
def assembleTask = tasks.getByName("assemble$variantCapitalized")
def licenseTask = tasks.getByName("license${variantCapitalized}Report")
assembleTask.dependsOn licenseTask
}
android {
compileSdkVersion 26
defaultConfig {
applicationId "io.supercharge.myapplication"
minSdkVersion 21
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
}
output open_source_licenses.html
<html>
<head>
<style>body{font-family: sans-serif} pre{background-color: #eeeeee; padding: 1em; white-space: pre-wrap}</style>
<title>Open source licenses</title>
</head>
<body>
<h3>None</h3>
</body>
</html>
output open_source_licenses.json
[]
Some projects like okHttp
seems to not codify versions directly, but in the parent pom files that have a 1:1 mapping with each release.
I can't tell if this is in accordance to the pom spec. But the maven plugin for gradle itself seems to honor this codification.
<parent>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>parent</artifactId>
<version>3.12.1</version>
</parent>
The problem I see if that the license plugin has versions set to null, which is frankly quite reasonable.
{
"project": "OkHttp",
"description": null,
"version": null
}
Could we have this pickup the version from the parent pom instead ?
When I create an empty sample project in Android Studio and run the licenseReleaseReport I get the following error:
Error:Execution failed for task ':app:licenseDebugReport'.
> Could not resolve all dependencies for configuration ':app:poms'.
> Could not find :unspecified:.
Searched in the following locations:
file:/C:/Users/user/AppData/Local/Android/Sdk/extras/m2repository//unspecified//unspecified-.pom
file:/C:/Users/user/AppData/Local/Android/Sdk/extras/m2repository//unspecified//unspecified-.pom
file:/C:/Users/user/AppData/Local/Android/Sdk/extras/google/m2repository//unspecified//unspecified-.pom
file:/C:/Users/user/AppData/Local/Android/Sdk/extras/google/m2repository//unspecified//unspecified-.pom
file:/C:/Users/user/AppData/Local/Android/Sdk/extras/android/m2repository//unspecified//unspecified-.pom
file:/C:/Users/user/AppData/Local/Android/Sdk/extras/android/m2repository//unspecified//unspecified-.pom
file:/E:/Android Studio/gradle/m2repository//unspecified//unspecified-.pom
file:/E:/Android Studio/gradle/m2repository//unspecified//unspecified-.pom
https://jcenter.bintray.com//unspecified//unspecified-.pom
https://jcenter.bintray.com//unspecified//unspecified-.pom
Required by:
project :app
I get "Error:(123, 0) Could not find method licenseReport() for arguments [build_cqkmblnzf6152h2yrw5tqbk5i$_run_closure2@234d2d61] on project ':app' of type org.gradle.api.Project."
When trying to use configuration using version 0.8.0.
licenseReport {
generateHtmlReport = false
generateJsonReport = true
copyHtmlReportToAssets = false
copyJsonReportToAssets = true
}
(I only want a JSON report copied to assets, not the html report)
I tried the same thing using the 0.8.1-SNAPSHOT version and then it works just fine.
Any ETA for a release of 0.8.1 so I do not need to use a snapshot version?
Hi, this is not a request but rather I would like to know your thought about publishing this plugin to Maven Central as well?
Jcenter has some recent changes that break builds and there have been some public debates about switching from jcenter()
to mavenCentral()
(or google()
when appropriate), which I'd rather not quote here.
I think it would be nice if there is an option to adopt this plugin via Maven Central as well, if that's possible at all.
debugCompile
and releaseCompile
can no longer be resolved directly. Here is the error message:
* What went wrong:
Execution failed for task ':app:licenseProductionDevSdkDebugReport'.
> Resolving configuration 'debugCompile' directly is not allowed
The stacktrace reveals that this is coming from LicenseReportTask.groovy:68
.
This allows the plugin to easily handle duplicates and projects with multiple licenses.
Apache
BSD
Eclipse
If a dependency exists but doesn't have a pom associated with it, this plugin will not include the dependency in either the HTML or JSON reports, or in the console logging.
We get logging when a dependency doesn't have any license info listed in the pom, but nothing is logged when the pom itself is not found.
In a project with a few different build variants, running a full gradle build
results in a crash.
The crash seems to be caused by each variant's license task conflicting with one another. When the first license task runs, it creates a configuration called 'poms'. Then when the second variant's license task runs, it attempts to create the same configuration, which crashes since it already exists.
Here's a small example app that demos this issue: https://github.com/egargan/license-plugin-issue-demo.
The error output can be viewed in the /gradle-build-error-output file. The /app/build.gradle file sets up the calls to each task.
I like that this plugin can generate license reports for the different build-variants. But I often have a lot of them and it would be great to have one task that generates the license infos for all variants.
This issue only exist for me to reference in an incoming pull request.
Is it possible to add TEXT based reports in this plugin?
I'm using v0.8.41, gradle v4.5.1, android plugin v3.0.1.
My applied plugins are:
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
apply plugin: 'realm-android'
apply plugin: 'io.fabric'
apply plugin: 'com.jaredsburrows.license'
My licenseReport
extension is:
licenseReport {
generateHtmlReport = false
generateJsonReport = true
// These options are ignored for Java projects
copyHtmlReportToAssets = false
copyJsonReportToAssets = false
}
If I run :app:license<my flavor>DebugReport
it completes and logs that it wrote the json report, but opening that file just shows []
.
My dependencies are a mix of local modules, and maven artifacts.
Hi there,
I would like to thanks Jared Burrows for this awesome project.
I have question about using this project.
apply plugin: "com.jaredsburrows.license"
licenseReport {
ignoreModules = ["...", "...", "..."]
}
or something equals or relevant?
${project.groupId}.${project.artifactId}
show up in accident.${project.groupId}.${project.artifactId}
using Apache License ๐)Can I detach it from gradle config? or I need to edit HTMLs manually?
Thanks.
After enabling Jetifier and Androidx into my project, the license report shows empty results. I tried printing the productFlavours in LicensePlugin, which gives an empty result. here is the POC which demos this behavior. Investigating too as to why this issue prevails.
Based on #15 (comment), show warnings for when the plugin "misses" or "skips" a dependency.
:emp-api:licenseReport FAILED
FAILURE: Build failed with an exception.
Could not find property 'canBeResolved' on configuration ':emp-api:compile'.
I'm trying with the following configurations :
licenseReport {
generateHtmlReport = true
// These options are ignored for Java projects
copyHtmlReportToAssets = true
}
however I get the following error, with an empty HTMLReport file.
Execution failed for task ':app:licenseReleaseReport'.
> > Task :app:licenseReleaseReport
saimos-unit-api dependency does not have a license.
saimos-common dependency does not have a license.
> Task :app:licenseReleaseReport FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:licenseReleaseReport'.
> HtmlReport::class.java.gโฆFile.separatorChar)
) must not be null
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
when I use the Json configuration, json is generated with no issues.
README says:
repositories {
jcenter()
}
compile "com.jaredsburrows:gradle-license-plugin:0.4.0"
But it should say:
dependencies {
classpath "com.jaredsburrows:gradle-license-plugin:0.4.0"
}
apply plugin: 'com.jaredsburrows.license'
Or am I wrong? I can make a PR if you want.
I tried the gradle-license-plugin for a pure Kotlin project. However, I get the following error message:
An exception occurred applying plugin request [id: 'com.jaredsburrows.license', version: '0.7.0']
> Failed to apply plugin [id 'com.jaredsburrows.license']
> License report plugin can only be applied to android or java projects.
Following situation:
There is an app which consist of two modules: app itself and SDK it's being built upon.
If I apply this plugin to both modules, it will 2 create assets/open_source_licenses.html files -one per module. So when I build the APK, one of the files is naturally lost.
Solution that would work in my case is to have for example automatic naming per module: like assets/open_source_licenses_sdk.html
Thanks.
on Android
classpath 'com.android.tools.build:gradle:3.0.0-beta7'
gradle-4.1-all.zip
What went wrong:
Execution failed for task ':PayTVApp:licenseMovistarGO_PE_DebugReport'.
Resolving configuration 'debugCompile' directly is not allowed
Try:
Run with --info or --debug option to get more log output.
Exception is:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ''.
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:100)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:70)
at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:63)
at org.gradle.api.internal.tasks.execution.ResolveTaskOutputCachingStateExecuter.execute(ResolveTaskOutputCachingStateExecuter.java:54)
at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58)
at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:88)
at org.gradle.api.internal.tasks.execution.ResolveTaskArtifactStateTaskExecuter.execute(ResolveTaskArtifactStateTaskExecuter.java:52)
at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52)
at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:54)
at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:34)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker$1.run(DefaultTaskGraphExecuter.java:248)
at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:336)
at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:328)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:197)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:107)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:241)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:230)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.processTask(DefaultTaskPlanExecutor.java:124)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.access$200(DefaultTaskPlanExecutor.java:80)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker$1.execute(DefaultTaskPlanExecutor.java:105)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker$1.execute(DefaultTaskPlanExecutor.java:99)
at org.gradle.execution.taskgraph.DefaultTaskExecutionPlan.execute(DefaultTaskExecutionPlan.java:625)
at org.gradle.execution.taskgraph.DefaultTaskExecutionPlan.executeWithTask(DefaultTaskExecutionPlan.java:580)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.run(DefaultTaskPlanExecutor.java:99)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
Caused by: java.lang.IllegalStateException: Resolving configuration 'debugCompile' directly is not allowed
at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.assertResolvingAllowed(DefaultConfiguration.java:888)
at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.resolveToStateOrLater(DefaultConfiguration.java:434)
at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.getResolvedConfiguration(DefaultConfiguration.java:429)
at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration_Decorated.getResolvedConfiguration(Unknown Source)
at org.gradle.internal.metaobject.BeanDynamicObject$MetaClassAdapter.getProperty(BeanDynamicObject.java:228)
at org.gradle.internal.metaobject.BeanDynamicObject.tryGetProperty(BeanDynamicObject.java:171)
at org.gradle.internal.metaobject.CompositeDynamicObject.tryGetProperty(CompositeDynamicObject.java:55)
at org.gradle.internal.metaobject.AbstractDynamicObject.getProperty(AbstractDynamicObject.java:59)
at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration_Decorated.getProperty(Unknown Source)
at com.jaredsburrows.license.LicenseReportTask$_generatePOMInfo_closure2.doCall(LicenseReportTask.groovy:68)
at com.jaredsburrows.license.LicenseReportTask.generatePOMInfo(LicenseReportTask.groovy:67)
at com.jaredsburrows.license.LicenseReportTask.licenseReport(LicenseReportTask.groovy:37)
at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:73)
at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.doExecute(DefaultTaskClassInfoStore.java:141)
at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.execute(DefaultTaskClassInfoStore.java:134)
at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.execute(DefaultTaskClassInfoStore.java:121)
at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:731)
at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:705)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$1.run(ExecuteActionsTaskExecuter.java:122)
at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:336)
at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:328)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:197)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:107)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:111)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:92)
... 27 more
any ideas?
thank you
Android tests fail when running on Windows.
This seems to be due to Windows paths for the temporary generated projects being written to local.properties without escaping backslashes.
I have a fix for this. Will submit a pull request shortly.
$ ./gradlew licenseDebugReport
:blah:licenseDebugReport FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':blah:licenseDebugReport'.
> Could not resolve all dependencies for configuration ':blah:poms'.
> Could not find blah:unspecified.
Searched in the following locations:
https://plugins.gradle.org/blah-unspecified.pom
file:/Users/<>/blah-unspecified.pom
http://dl.bintray.com/blah-unspecified.pom
https://repo1.maven.org/blah-unspecified.pom
https://jcenter.bintray.com/blah-unspecified.pom
Required by:
project :blah
It would be nice to have the year and developer shown for each entry in the HTML file.
Also the License in the HTML looks a little bit off, since the String "Copyright [yyyy] [name of copyright owner]" is not really appealing.
I myself got no experience in groovy, so it would be nice if you could have a look at the issue.
Hi,
great Job with you Lib! This lib help me a lot to generating my open source view automatically. Thank you!
I found one big problem:
Some dependencies (square etc.) in generated JSON and HTML file are missing.
Dependencies:
// Support
compile "com.android.support:appcompat-v7:${supportVersion}"
compile "com.android.support:design:${supportVersion}"
compile "com.android.support:support-v13:${supportVersion}"
compile "com.android.support:percent:${supportVersion}"
compile "com.android.support:recyclerview-v7:${supportVersion}"
//Annotations
apt "org.androidannotations:androidannotations:${androidannotationsVersion}"
compile "org.androidannotations:androidannotations-api:${androidannotationsVersion}"
// Network
compile "com.squareup.retrofit2:retrofit:${retrofitVersion}"
compile "com.squareup.retrofit2:converter-gson:${retrofitVersion}"
compile "com.squareup.okhttp3:logging-interceptor:${okhttpVersion}"
compile "com.squareup.okhttp3:okhttp:${okhttpVersion}"
compile "com.squareup.okhttp3:okhttp-urlconnection:${okhttpVersion}"
compile "com.github.bumptech.glide:glide:3.7.0"
compile 'com.github.bumptech.glide:okhttp3-integration:1.4.0@aar'
// View
compile 'me.relex:circleindicator:1.2.1@aar'
compile 'eu.davidea:flexible-adapter:5.0.0-b8'
compile 'cn.aigestudio.wheelpicker:WheelPicker:1.1.2'
compile 'com.daimajia.swipelayout:library:1.2.0@aar'
compile 'de.hdodenhof:circleimageview:2.1.0'
// Fonts
compile 'uk.co.chrisjenx:calligraphy:2.3.0'
// DevOps
compile "net.hockeyapp.android:HockeySDK:${hockeyApp}"
// Logging
compile "org.slf4j:slf4j-android:${slf4jVersion}"
// Chuck Interceptor
debugCompile "com.readystatesoftware.chuck:library:${chuckVersion}"
debug_testCompile "com.readystatesoftware.chuck:library:${chuckVersion}"
alphaCompile "com.readystatesoftware.chuck:library-no-op:${chuckVersion}"
betaCompile "com.readystatesoftware.chuck:library-no-op:${chuckVersion}"
showcaseCompile "com.readystatesoftware.chuck:library-no-op:${chuckVersion}"
qsCompile "com.readystatesoftware.chuck:library-no-op:${chuckVersion}"
releaseCompile "com.readystatesoftware.chuck:library-no-op:${chuckVersion}"
// Leak Canary
debugCompile "com.squareup.leakcanary:leakcanary-android:${leakCanaryVersion}"
debug_testCompile "com.squareup.leakcanary:leakcanary-android:${leakCanaryVersion}"
alphaCompile "com.squareup.leakcanary:leakcanary-android-no-op:${leakCanaryVersion}"
betaCompile "com.squareup.leakcanary:leakcanary-android-no-op:${leakCanaryVersion}"
showcaseCompile "com.squareup.leakcanary:leakcanary-android-no-op:${leakCanaryVersion}"
qsCompile "com.squareup.leakcanary:leakcanary-android-no-op:${leakCanaryVersion}"
releaseCompile "com.squareup.leakcanary:leakcanary-android-no-op:${leakCanaryVersion}"
testCompile "com.squareup.leakcanary:leakcanary-android-no-op:${leakCanaryVersion}"
Generated JSON:
[
{
"project": "Android SwipeLayout Library",
"developers": "daimajia",
"url": "https://github.com/daimajia/AndroidSwipeLayout",
"year": null,
"license": "MIT",
"license_url": "http://opensource.org/licenses/MIT"
},
{
"project": "Animated-vector-drawable",
"developers": null,
"url": null,
"year": null,
"license": "The Apache Software License",
"license_url": "http://www.apache.org/licenses/LICENSE-2.0.txt"
},
{
"project": "Appcompat-v7",
"developers": null,
"url": null,
"year": null,
"license": "The Apache Software License",
"license_url": "http://www.apache.org/licenses/LICENSE-2.0.txt"
},
{
"project": "Calligraphy",
"developers": "Christopher Jenkins",
"url": "https://github.com/chrisjenx/Calligraphy",
"year": null,
"license": "The Apache Software License, Version 2.0",
"license_url": "http://www.apache.org/licenses/LICENSE-2.0.txt"
},
{
"project": "Chuck no-op",
"developers": "Jeff Gilfelt",
"url": "https://github.com/jgilfelt/chuck",
"year": null,
"license": "The Apache Software License, Version 2.0",
"license_url": "http://www.apache.org/licenses/LICENSE-2.0.txt"
},
{
"project": "CircleImageView",
"developers": "Henning Dodenhof",
"url": "https://github.com/hdodenhof/CircleImageView",
"year": null,
"license": "The Apache Software License, Version 2.0",
"license_url": "http://www.apache.org/licenses/LICENSE-2.0.txt"
},
{
"project": "CircleIndicator",
"developers": "relex",
"url": "https://github.com/ongakuer/CircleIndicator",
"year": null,
"license": "The Apache Software License, Version 2.0",
"license_url": "http://www.apache.org/licenses/LICENSE-2.0.txt"
},
{
"project": "Design",
"developers": null,
"url": null,
"year": null,
"license": "The Apache Software License",
"license_url": "http://www.apache.org/licenses/LICENSE-2.0.txt"
},
{
"project": "FlexibleAdapter",
"developers": "Davide Steduto",
"url": "https://github.com/davideas/FlexibleAdapter",
"year": null,
"license": "The Apache Software License, Version 2.0",
"license_url": "http://www.apache.org/licenses/LICENSE-2.0.txt"
},
{
"project": "Glide",
"developers": "Sam Judd",
"url": "https://github.com/bumptech/glide",
"year": null,
"license": "Simplified BSD License",
"license_url": "http://www.opensource.org/licenses/bsd-license"
},
{
"project": "Glide OkHttp 3.x Integration",
"developers": "Sam Judd",
"url": "https://github.com/bumptech/glide",
"year": null,
"license": "Simplified BSD License",
"license_url": "http://www.opensource.org/licenses/bsd-license"
},
{
"project": "Hugo Annotations",
"developers": "Jake Wharton",
"url": "https://github.com/JakeWharton/hugo/",
"year": null,
"license": "The Apache Software License, Version 2.0",
"license_url": "http://www.apache.org/licenses/LICENSE-2.0.txt"
},
{
"project": "No op LeakCanary for Android",
"developers": "Square, Inc.",
"url": "http://github.com/square/leakcanary/",
"year": null,
"license": "The Apache Software License, Version 2.0",
"license_url": "http://www.apache.org/licenses/LICENSE-2.0.txt"
},
{
"project": "Percent",
"developers": null,
"url": null,
"year": null,
"license": "The Apache Software License",
"license_url": "http://www.apache.org/licenses/LICENSE-2.0.txt"
},
{
"project": "ReLinker",
"developers": "KeepSafe",
"url": "https://github.com/KeepSafe/ReLinker",
"year": "2015",
"license": "The Apache Software License, Version 2.0",
"license_url": "http://www.apache.org/licenses/LICENSE-2.0.txt"
},
{
"project": "Realm-annotations",
"developers": null,
"url": "scm:https://github.com/realm/realm-java",
"year": null,
"license": "The Apache Software License, Version 2.0",
"license_url": "http://www.apache.org/licenses/LICENSE-2.0.txt"
},
{
"project": "Recyclerview-v7",
"developers": null,
"url": null,
"year": null,
"license": "The Apache Software License",
"license_url": "http://www.apache.org/licenses/LICENSE-2.0.txt"
},
{
"project": "SLF4J API and Google Android Binding",
"developers": "Thorsten M\u00f6ller",
"url": null,
"year": "2009",
"license": "The MIT License",
"license_url": "http://www.opensource.org/licenses/mit-license.php"
},
{
"project": "Simple and fantastic wheel view in realistic effect for android",
"developers": "Aige",
"url": "https://github.com/AigeStudio/WheelPicker",
"year": null,
"license": "The Apache Software License, Version 2.0",
"license_url": "http://www.apache.org/licenses/LICENSE-2.0.txt"
},
{
"project": "Support-annotations",
"developers": null,
"url": null,
"year": null,
"license": "The Apache Software License",
"license_url": "http://www.apache.org/licenses/LICENSE-2.0.txt"
},
{
"project": "Support-compat",
"developers": null,
"url": null,
"year": null,
"license": "The Apache Software License",
"license_url": "http://www.apache.org/licenses/LICENSE-2.0.txt"
},
{
"project": "Support-core-ui",
"developers": null,
"url": null,
"year": null,
"license": "The Apache Software License",
"license_url": "http://www.apache.org/licenses/LICENSE-2.0.txt"
},
{
"project": "Support-core-utils",
"developers": null,
"url": null,
"year": null,
"license": "The Apache Software License",
"license_url": "http://www.apache.org/licenses/LICENSE-2.0.txt"
},
{
"project": "Support-fragment",
"developers": null,
"url": null,
"year": null,
"license": "The Apache Software License",
"license_url": "http://www.apache.org/licenses/LICENSE-2.0.txt"
},
{
"project": "Support-media-compat",
"developers": null,
"url": null,
"year": null,
"license": "The Apache Software License",
"license_url": "http://www.apache.org/licenses/LICENSE-2.0.txt"
},
{
"project": "Support-v13",
"developers": null,
"url": null,
"year": null,
"license": "The Apache Software License",
"license_url": "http://www.apache.org/licenses/LICENSE-2.0.txt"
},
{
"project": "Support-v4",
"developers": null,
"url": null,
"year": null,
"license": "The Apache Software License",
"license_url": "http://www.apache.org/licenses/LICENSE-2.0.txt"
},
{
"project": "Support-vector-drawable",
"developers": null,
"url": null,
"year": null,
"license": "The Apache Software License",
"license_url": "http://www.apache.org/licenses/LICENSE-2.0.txt"
},
{
"project": "Transition",
"developers": null,
"url": null,
"year": null,
"license": "The Apache Software License",
"license_url": "http://www.apache.org/licenses/LICENSE-2.0.txt"
}
]
Hello,
I'm trying to run licenseDebugReport or licenseReleaseReport on my Android app using Gradle 4.0 and Android Plugin Version 3.0.0-alpha2. The task fails to run, see error report below:
arocha$ ./gradlew :android:licenseDebugReport --stacktrace
Parallel execution with configuration on demand is an incubating feature.
Configuration 'compile' in project ':android' is deprecated. Use 'implementation' instead.
:android:licenseDebugReport FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':android:licenseDebugReport'.
> Resolving configuration 'debugCompile' directly is not allowed
* Try:
Run with --info or --debug option to get more log output.
* Exception is:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':android:licenseDebugReport'.
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:98)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:68)
at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:60)
at org.gradle.api.internal.tasks.execution.ResolveTaskOutputCachingStateExecuter.execute(ResolveTaskOutputCachingStateExecuter.java:54)
at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58)
at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:88)
at org.gradle.api.internal.tasks.execution.ResolveTaskArtifactStateTaskExecuter.execute(ResolveTaskArtifactStateTaskExecuter.java:52)
at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52)
at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:54)
at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:34)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker$1.execute(DefaultTaskGraphExecuter.java:248)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker$1.execute(DefaultTaskGraphExecuter.java:239)
at org.gradle.internal.Transformers$4.transform(Transformers.java:169)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:114)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:68)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:239)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:226)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.processTask(DefaultTaskPlanExecutor.java:120)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.access$200(DefaultTaskPlanExecutor.java:77)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker$1.execute(DefaultTaskPlanExecutor.java:101)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker$1.execute(DefaultTaskPlanExecutor.java:95)
at org.gradle.execution.taskgraph.DefaultTaskExecutionPlan.executeWithTask(DefaultTaskExecutionPlan.java:527)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.run(DefaultTaskPlanExecutor.java:95)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
at org.gradle.internal.concurrent.StoppableExecutorImpl$1.run(StoppableExecutorImpl.java:46)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
Caused by: java.lang.IllegalStateException: Resolving configuration 'debugCompile' directly is not allowed
at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.assertResolvingAllowed(DefaultConfiguration.java:885)
at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.resolveToStateOrLater(DefaultConfiguration.java:458)
at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.getResolvedConfiguration(DefaultConfiguration.java:453)
at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration_Decorated.getResolvedConfiguration(Unknown Source)
at org.gradle.internal.metaobject.BeanDynamicObject$MetaClassAdapter.getProperty(BeanDynamicObject.java:228)
at org.gradle.internal.metaobject.BeanDynamicObject.tryGetProperty(BeanDynamicObject.java:171)
at org.gradle.internal.metaobject.CompositeDynamicObject.tryGetProperty(CompositeDynamicObject.java:55)
at org.gradle.internal.metaobject.AbstractDynamicObject.getProperty(AbstractDynamicObject.java:59)
at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration_Decorated.getProperty(Unknown Source)
at com.jaredsburrows.license.LicenseReportTask$_generatePOMInfo_closure2.doCall(LicenseReportTask.groovy:68)
at com.jaredsburrows.license.LicenseReportTask.generatePOMInfo(LicenseReportTask.groovy:67)
at com.jaredsburrows.license.LicenseReportTask.licenseReport(LicenseReportTask.groovy:37)
at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:73)
at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.doExecute(DefaultTaskClassInfoStore.java:139)
at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.execute(DefaultTaskClassInfoStore.java:132)
at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.execute(DefaultTaskClassInfoStore.java:121)
at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:706)
at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:689)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$1.execute(ExecuteActionsTaskExecuter.java:115)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$1.execute(ExecuteActionsTaskExecuter.java:109)
at org.gradle.internal.Transformers$4.transform(Transformers.java:169)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:114)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:63)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:109)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:90)
... 26 more
BUILD FAILED in 0s
1 actionable task: 1 executed, 0 avoided (0%)
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':android:licenseDebugReport'.
> Resolving configuration 'debugCompile' directly is not allowed
I was not having this issue prior to updating to Gradle 4.0. Any ETA on when can we expect support for latest Gradle version?
Thanks,
Alex
Example:
<licenses>
<license>
<name>NA</name>
<url>NA</url>
<distribution>repo</distribution>
</license>
</licenses>
The plugin cannot valid names but at least I can try to validate actual URLs to prevent generating reports with "NA, NA".
For example, in my project, we use Apache HttpCore, and the JSON file contains this entry:
{
"project": "Apache HttpCore",
"description": "Apache HttpComponents Core (blocking I/O)",
"version": null,
"developers": [
],
"url": "http://hc.apache.org/httpcomponents-core-ga",
"year": "2005",
"licenses": [
{
"license": "Apache License, Version 2.0",
"license_url": "http://www.apache.org/licenses/LICENSE-2.0.txt"
}
]
},
Version should be extractible from some location. For example, plugin "Gradle-License-Report" managed to figure out that in my project we use httpcore 4.4.9 (they titled it "Manifest version"). That plugin does not feature a JSON report mode, which is why I wanted to use your plugin, but sadly the JSON report doesn't specify the version for many of our dependencies.
Your efforts will be highly appreciated, keep up the good work, and thanks for the plugin :)
Following dependencies are used:
compile 'com.android.support:support-v4:25.3.1'
compile 'com.android.support:multidex:1.0.1'
compile 'com.squareup.retrofit:retrofit:1.9.0'
compile 'com.squareup.okhttp3:okhttp:3.8.1'
compile 'com.google.firebase:firebase-messaging:10.0.1'
compile 'com.googlecode.libphonenumber:libphonenumber:8.4.2'
But firebase does not manage to be included in the report:
Is there is may be something specific at the fact how firebase license file is published?
Could you shortly explain how the plugin works, where it takes the license info?
I'm seeing the following warning, which wouldn't concern me except for the end-of-year deadline:
WARNING: API 'variant.getMergeResources()' is obsolete and has been replaced with 'variant.getMergeResourcesProvider()'.
It will be removed at the end of 2019.
For more information, see https://d.android.com/r/tools/task-configuration-avoidance.
To determine what is calling variant.getMergeResources(), use -Pandroid.debug.obsoleteApi=true on the command line to display more information.
Donn
I just generated a report and noticed that the Apache License 2.0 shows up in there twice. The first time for:
The license text section in both is identical. So I had a look at the json, Mapdb here:
{
"project": "Mapdb",
"description": "MapDB provides concurrent Maps, Sets and Queues backed by disk storage or off-heap memory. It is a fast, scalable and easy to use embedded Java database.",
"version": "3.0.5",
"developers": [
"Jan Kotek"
],
"url": "http://www.mapdb.org",
"year": null,
"licenses": [
{
"license": "The Apache Software License, Version 2.0",
"license_url": "http://www.apache.org/licenses/LICENSE-2.0.txt"
}
]
},
And now log4j:
{
"project": "Apache Log4j API",
"description": "The Apache Log4j API",
"version": null,
"developers": [
],
"url": null,
"year": null,
"licenses": [
{
"license": "Apache License, Version 2.0",
"license_url": "https://www.apache.org/licenses/LICENSE-2.0.txt"
}
]
},
Both license URLs are exactly the same, except for the https.
I have an android project (with AGP 3.2.0) with a lot of library modules. I would like to have all dependencies in one file. Is this currently possible? I would like to apply the plugin to the root gradle file, so it can check all modules.
At the moment I will get one licence report per module.
For this I added the plugin in all modules.
Hi. Thanks for the plugin, it's been quite useful.
I got this strange requirement of reporting a very detailed licensing information each dependency including the transitive ones. That adds up to about ~180 dependencies, which means it's better be automated.
I managed to compile something using your library and a python script using the output json but there is still a lot to do. I noticed there are quite a lot more useful fields in pom files. I thought I could just get them but maven inheritance seems a little complex to deal with and you seem to have already implemented the traversing logic.
On a quick look these could be useful though some of them are maybe too much detail. Just gonna give examples from jersey project's POM instead of explaining
<name>jersey</name>
Children of the project will have more specific names of course.<url>https://jersey.java.net/</url>
<organization><name>Oracle Corporation</name><url>http://www.oracle.com/</url></organization>
<mailingLists><mailingList><name>Announcements</name><archive>http://java.net/projects/jersey/lists/announce/archive</archive><post>[email protected]</post></mailingList>.....
<scm><connection>scm:git:git://java.net/jersey~code</connection><developerConnection>scm:git:ssh://git.java.net/jersey~code</developerConnection><url>http://java.net/projects/jersey/sources/code/show</url><tag>2.25.1</tag></scm>
<issueManagement><system>JIRA</system><url>http://java.net/jira/browse/JERSEY/</url></issueManagement>
<ciManagement><system>Hudson</system><url>http://hudson.glassfish.org/job/Jersey-trunk-multiplatform/</url></ciManagement>
<developers><developer><name>Pavel Bucek</name><organization>Oracle Corporation</organization><organizationUrl>http://www.oracle.com/</organizationUrl><url>https://blogs.oracle.com/PavelBucek</url></developer>.....
Also specific to my use case but maybe.. A list of dependencies that depends on this dependency. Could be built while traversing. It is already provided by dependencies
task of gradle but not really in a scripting friendly way.
I could try to take a shot at this and make a PR but my 0 experience with Groovy made it quite difficult to read the code when I was trying to figure out where you were getting the licensing information. So the result might be a little ugly :).
Actually two bugs here, both in HtmlReport#getLicenseText
I get the following in the generated json:
{
"project": "Org.jetbrains.kotlin:kotlin-stdlib-common",
"description": "Kotlin Common Standard Library",
"version": "1.3.21",
"developers": [
"Kotlin Team"
],
"url": "https://kotlinlang.org/",
"year": null,
"licenses": [
{
"license": "The Apache License, Version 2.0",
"license_url": "http://www.apache.org/licenses/LICENSE-2.0.txt"
}
]
},
I think the Org
looks really off and it should not be capitalized.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.