{"action":"created","issue":{"url":"https://api.github.com/repos/jaredsburrows/AndroidGradleTemplate/issues/13","labels_url":"https://api.github.com/repos/jaredsburrows/AndroidGradleTemplate/issues/13/labels{/name}","comments_url":"https://api.github.com/repos/jaredsburrows/AndroidGradleTemplate/issues/13/comments","events_url":"https://api.github.com/repos/jaredsburrows/AndroidGradleTemplate/issues/13/events","html_url":"https://github.com/jaredsburrows/AndroidGradleTemplate/issues/13","id":83367248,"number":13,"title":"[Contribute] Static code analysis","user":{"login":"OleksandrKucherenko","id":6419758,"avatar_url":"https://avatars.githubusercontent.com/u/6419758?v=3","gravatar_id":"","url":"https://api.github.com/users/OleksandrKucherenko","html_url":"https://github.com/OleksandrKucherenko","followers_url":"https://api.github.com/users/OleksandrKucherenko/followers","following_url":"https://api.github.com/users/OleksandrKucherenko/following{/other_user}","gists_url":"https://api.github.com/users/OleksandrKucherenko/gists{/gist_id}","starred_url":"https://api.github.com/users/OleksandrKucherenko/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/OleksandrKucherenko/subscriptions","organizations_url":"https://api.github.com/users/OleksandrKucherenko/orgs","repos_url":"https://api.github.com/users/OleksandrKucherenko/repos","events_url":"https://api.github.com/users/OleksandrKucherenko/events{/privacy}","received_events_url":"https://api.github.com/users/OleksandrKucherenko/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":3,"created_at":"2015-06-01T07:46:05Z","updated_at":"2015-06-01T21:09:13Z","closed_at":null,"body":"Lint + TestResults + Jacoco\r\n\r\nWhat script do:\r\n1) create a new groups of tasks ```Reporting``` and ```Reporting routine```\r\n2) register global/aggregating tasks - ```checkOPenResults```, ```lintOpenResults```, ```testOpenResults```, ```jacocoOpenResults```\r\n3) create a set of tasks for each flavor, those tasks can be used for getting reports of the specific flavor\r\n\r\nScript expect several things:\r\n1) declaration of several global properties: ENABLE_QUALITY, useTesting, useJacoco\r\n2) script uses external bash script for executing reports opening in web browser ```open-test-results.sh```\r\n\r\n```groovy\r\n\r\n// tools: Code Analysis Tools\r\n\r\nimport org.apache.tools.ant.taskdefs.condition.Os\r\n\r\nbuildscript {\r\n  repositories {\r\n    jcenter()\r\n    mavenLocal()\r\n    mavenCentral()\r\n  }\r\n  dependencies {\r\n    // https://github.com/aaschmid/gradle-cpd-plugin\r\n    classpath 'de.aaschmid.gradle.plugins:gradle-cpd-plugin:+'\r\n  }\r\n}\r\n\r\ntask checkOpenResults(dependsOn: ['check']) {\r\n  description = 'Open reports of ALL attached Quality Tools in Web browser'\r\n  group = 'Reporting'\r\n\r\n  // do nothing, it used for dependency graph building only\r\n}\r\n\r\nif (ENABLE_QUALITY) {\r\n  /* [ LINT ] ===================================================================================================== */\r\n  task lintOpenResults(dependsOn: ['lint']) {\r\n    description = 'Open all reports for all flavors and build configurations.'\r\n    group = 'Reporting'\r\n  }\r\n  checkOpenResults.dependsOn lintOpenResults\r\n  afterEvaluate { iterateVariants(this.&createLintOpenResultsTask) }\r\n}\r\n\r\n/* [ UNIT Test Results ] ======================================================================================== */\r\nif (ENABLE_QUALITY && useTesting) {\r\n  task testOpenResults(dependsOn: ['test']) {\r\n    description = 'Open all Unit Tests results  for all flavors and build types.'\r\n    group = 'Reporting'\r\n  }\r\n  checkOpenResults.dependsOn testOpenResults\r\n  afterEvaluate { iterateVariants(this.&createTestOpenResultsTask) }\r\n}\r\n\r\n/* [ JACOCO coverage ] ========================================================================================== */\r\nif (ENABLE_QUALITY && useTesting && useJacoco) {\r\n  // Helpers:\r\n  //  http://forums.gradle.org/gradle/topics/gradle_1_6_jacoco_in_multi_module_build\r\n  //  http://goo.gl/1ZrSl0 --> JacocoPlugin.groovy\r\n  //  http://goo.gl/0pkjse --> JacocoReportTask.groovy\r\n\r\n  task jacocoOpenResults(dependsOn: ['test']) {\r\n    // Task opens report file in default web-browser\r\n    description = 'open Code Coverage for Unit Tests in web browser'\r\n    group = 'Reporting'\r\n  }\r\n  checkOpenResults.dependsOn jacocoOpenResults\r\n  afterEvaluate { iterateVariants(this.&createJacocoOpenResultsTask) }\r\n}\r\n\r\n/* [ HELPERS ] ====================================================================================================== */\r\n\r\ndef adoptToOs(String path) {\r\n  if (Os.isFamily(Os.FAMILY_WINDOWS)) { // windows\r\n    path = path.replace(\"/\", \"\\\\\")\r\n  } else if (Os.isFamily(Os.FAMILY_UNIX)) { // linux\r\n    path = path.replace(\"\\\\\", \"/\")\r\n  } else if (Os.isFamily(Os.FAMILY_MAC)) { // mac os\r\n    path = path.replace(\"\\\\\", \"/\")\r\n  }\r\n\r\n  return path;\r\n}\r\n\r\ndef openExternalBrowser(String path) {\r\n  if (Os.isFamily(Os.FAMILY_WINDOWS)) { // windows\r\n    return ['cmd.exe', '/C', path]\r\n  } else if (Os.isFamily(Os.FAMILY_UNIX)) { // linux\r\n    return [\"${rootProject.rootDir}/gradle/open-test-results.sh\", path]\r\n  } else if (Os.isFamily(Os.FAMILY_MAC)) { // mac os\r\n    // TODO: implement me\r\n    return ['']\r\n  }\r\n}\r\n\r\ndef iterateVariants(func) {\r\n  if (project.android.productFlavors.size() > 0) {\r\n    project.android.productFlavors.each { f ->\r\n      iterateBuildTypes(f.name, func)\r\n    }\r\n  } else {\r\n    iterateBuildTypes('', func)\r\n  }\r\n}\r\n\r\ndef iterateBuildTypes(String flavor, func) {\r\n  project.android.buildTypes.each { b ->\r\n    func(flavor, b.name);\r\n  }\r\n}\r\n\r\n/* [ TASKS CREATORS ] =============================================================================================== */\r\n\r\ndef createLintOpenResultsTask(String f, String b) {\r\n  def flavor = f.capitalize()\r\n  def buildType = b.capitalize()\r\n  def taskName = \"openLintReport${flavor}${buildType}\"\r\n\r\n  project.task(taskName, type: Exec, dependsOn: [\"lint${flavor}${buildType}\"]) {\r\n    description = \"open lint${flavor}${buildType} results in current web browser.\"\r\n    group = 'Reporting Routine'\r\n\r\n    ignoreExitValue true // task is not critical, ignore it failure\r\n\r\n    // path is relative to current project path: {project}\\\\samples\\\\sample-01\r\n    // file:/C:/Android/_projects_/meter/samples/sample-01/build/outputs/lint-results.html\r\n    def lintFile = \"lint-results-${flavor}${buildType}-fatal.html\"\r\n    def path = \"\"\"${project.buildDir}\\\\outputs\\\\${lintFile}\"\"\"\r\n\r\n    project.logger.info(\"  report: ${adoptToOs(path)}\")\r\n    commandLine openExternalBrowser(adoptToOs(path))\r\n  }\r\n\r\n  lintOpenResults.dependsOn taskName\r\n}\r\n\r\ndef createTestOpenResultsTask(String f, String b) {\r\n  def flavor = f.capitalize()\r\n  def buildType = b.capitalize()\r\n  def taskName = \"openTestReport${flavor}${buildType}\"\r\n\r\n  project.task(taskName, type: Exec, dependsOn: [\"test${flavor}${buildType}\"]) {\r\n    // Task opens report file in default web-browser\r\n    description = 'open Unit Tests results in current web browser'\r\n    group = 'Reporting Routine'\r\n\r\n    ignoreExitValue true // task is not critical, ignore it failure\r\n\r\n    // path is relative to current project path: {project}\\\\samples\\\\sample-01\r\n    // file:///C:/Android/_projects_/meter/library/build/reports/tests/index.html\r\n    def path = \"\"\"${project.buildDir}\\\\reports\\\\tests\\\\${flavor}${buildType}\\\\index.html\"\"\"\r\n\r\n    project.logger.info(\"  report: ${adoptToOs(path)}\")\r\n    commandLine openExternalBrowser(adoptToOs(path))\r\n  }\r\n\r\n  testOpenResults.dependsOn taskName\r\n}\r\n\r\ndef createJacocoOpenResultsTask(String f, String b) {\r\n  def flavor = f.capitalize()\r\n  def buildType = b.capitalize()\r\n  def taskName = \"generateJacocoReport${flavor}${buildType}\"\r\n\r\n  project.task(taskName, type: JacocoReport, dependsOn: [\"test${flavor}${buildType}\"]) {\r\n    description = 'Generates Jacoco coverage reports: XML and HTML'\r\n    group = 'Reporting Routine'\r\n\r\n    // use hidden configuration, for details look into JacocoPlugin.groovy\r\n    jacocoClasspath = project.configurations['androidJacocoAnt']\r\n\r\n    // exclude auto-generated classes and tests\r\n    def fileFilter = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/*Test*.*', 'android/**/*.*', '**/Mock*.*']\r\n    def testsTree = fileTree(dir: \"${project.buildDir}/intermediates/classes/test/${flavor}/${buildType}\", excludes: fileFilter)\r\n    def flavorTree = fileTree(dir: \"${project.buildDir}/intermediates/classes/${flavor}/${buildType}\", excludes: fileFilter)\r\n\r\n    // sources\r\n    def testsSrc = \"${project.projectDir}/src/test/java\"\r\n    def testsFlavorSrc = \"${project.projectDir}/src/test${flavor}/java\"\r\n    def testsBuildSrc = \"${project.projectDir}/src/test${buildType}/java\"\r\n    def testsVariantSrc = \"${project.projectDir}/src/test${flavor}${buildType}/java\"\r\n    def mainSrc = \"${project.projectDir}/src/main/java\"\r\n\r\n    // TODO: confirm order of the src dirs\r\n    sourceDirectories = files([testsSrc, testsFlavorSrc, testsBuildSrc, testsVariantSrc, mainSrc])\r\n    classDirectories = files([testsTree, flavorTree])\r\n    executionData = fileTree(dir: project.projectDir, includes: ['**/*.exec', '**/*.ec'])\r\n\r\n    reports {\r\n      xml {\r\n        enabled = true\r\n        destination = \"${project.buildDir}/reports/jacoco/${flavor}/${buildType}/jacoco.xml\"\r\n      }\r\n      csv.enabled false\r\n      html {\r\n        enabled = true\r\n        destination = \"${project.buildDir}/reports/jacoco/${flavor}/${buildType}\"\r\n      }\r\n    }\r\n  }\r\n\r\n  def taskName2 = \"openJacocoReport${flavor}${buildType}\"\r\n  project.task(taskName2, type: Exec, dependsOn: [taskName]) {\r\n    // Task opens report file in default web-browser\r\n    description = 'open Code Coverage for Unit Tests in web browser'\r\n    group = 'Reporting Routine'\r\n\r\n    ignoreExitValue true // task is not critical, ignore it failure\r\n\r\n    def path = \"\"\"${project.buildDir}/reports/jacoco/${flavor}/${buildType}/index.html\"\"\"\r\n\r\n    rootProject.logger.info('  report: ' + path)\r\n    commandLine openExternalBrowser(adoptToOs(path))\r\n  }\r\n\r\n  jacocoOpenResults.dependsOn taskName2\r\n}\r\n\r\n```\r\n\r\n```bash\r\n#!/bin/bash\r\n\r\n## http://www.gnu.org/software/bash/manual/bashref.html\r\n## http://stackoverflow.com/questions/3124556/clean-way-to-launch-the-web-browser-from-shell-script\r\n## http://askubuntu.com/questions/8252/how-to-launch-default-web-browser-from-the-terminal\r\n\r\nexecutor=gnome-open\r\ntype gnome-open >/dev/null 2>&1 || {\r\n    echo >&2 \"gnome-open not installed.\";\r\n    executor=sensible-browser\r\n    type sensible-browser >/dev/null 2>&1 || {\r\n        echo >&2 \"sensible-browser not installed.\"\r\n        executor=x-www-browser\r\n        type x-www-browser >/dev/null 2>&1 || {\r\n            echo >&2 \"x-www-browser not installed.\";\r\n            executor=xdg-open\r\n            type xdg-open >/dev/null 2>&1 || {\r\n                echo >&2 \"xdg-open not installed. Aborting.\";\r\n                exit 1;\r\n            }\r\n        }\r\n    }\r\n}\r\n\r\nURL=$1\r\necho \"Found executor: $executor\"\r\n\r\n# run in background\r\nexec \"$executor\" \"$URL\" &\r\n\r\n```"},"comment":{"url":"https://api.github.com/repos/jaredsburrows/AndroidGradleTemplate/issues/comments/107713119","html_url":"https://github.com/jaredsburrows/AndroidGradleTemplate/issues/13#issuecomment-107713119","issue_url":"https://api.github.com/repos/jaredsburrows/AndroidGradleTemplate/issues/13","id":107713119,"user":{"login":"OleksandrKucherenko","id":6419758,"avatar_url":"https://avatars.githubusercontent.com/u/6419758?v=3","gravatar_id":"","url":"https://api.github.com/users/OleksandrKucherenko","html_url":"https://github.com/OleksandrKucherenko","followers_url":"https://api.github.com/users/OleksandrKucherenko/followers","following_url":"https://api.github.com/users/OleksandrKucherenko/following{/other_user}","gists_url":"https://api.github.com/users/OleksandrKucherenko/gists{/gist_id}","starred_url":"https://api.github.com/users/OleksandrKucherenko/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/OleksandrKucherenko/subscriptions","organizations_url":"https://api.github.com/users/OleksandrKucherenko/orgs","repos_url":"https://api.github.com/users/OleksandrKucherenko/repos","events_url":"https://api.github.com/users/OleksandrKucherenko/events{/privacy}","received_events_url":"https://api.github.com/users/OleksandrKucherenko/received_events","type":"User","site_admin":false},"created_at":"2015-06-01T21:09:13Z","updated_at":"2015-06-01T21:09:13Z","body":"Its already public and used in my other github projects. Feel free to use. \r\nif you mention my name on page - that will be great."}}