From 3e88cd466ca11e7e88c91697e64f13859b778000 Mon Sep 17 00:00:00 2001 From: Kengo TODA Date: Tue, 3 Mar 2020 14:37:39 +0800 Subject: [PATCH] Merge from staging repo to release v4.0.0 (#191) Replaced legacy implementation with new one implemented from scratch. BREAKING CHANGE: This version drop support for `emacs` reporting and `sourceSets` property in extension. It also changed the name of package, to avoid mixing with legacy implementation. --- .githooks/.gitignore | 20 + .githooks/post-checkout | 23 + .github/CONTRIBUTING.md | 40 + .github/FUNDING.yml | 1 + .github/auto-merge.yml | 6 + .github/issuehunt-shield-v1.svg | 85 + .github/workflows/gradle.yml | 63 + .github/workflows/javadoc.yml | 31 + .gitignore | 331 +- .idea/compiler.xml | 37 + .idea/google-java-format.xml | 6 + .idea/inspectionProfiles/Project_Default.xml | 6 + .idea/jarRepositories.xml | 30 + .idea/misc.xml | 5 + .idea/spotbugs-gradle-plugin-v2.iml | 9 + .idea/vcs.xml | 6 + .nvmrc | 4 + CHANGELOG.md | 167 - README.md | 111 +- RELEASE_PROCEDURE.md | 29 - build.gradle | 95 +- commitlint.config.js | 36 + gradle/HEADER.txt | 13 + gradle/checkstyle.gradle | 10 - gradle/checkstyle.xml | 9 - gradle/deploy.gradle | 47 - gradle/errorprone.gradle | 5 + gradle/functional-test.gradle | 32 + gradle/jacoco.gradle | 18 - gradle/java.gradle | 8 - gradle/publish.gradle | 29 + gradle/sonar.gradle | 10 - gradle/spotless.gradle | 24 +- gradle/spotless.sh | 19 + gradle/test.gradle | 36 + gradle/wrapper/gradle-wrapper.jar | Bin 55741 -> 58695 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 51 +- gradlew.bat | 18 +- package-lock.json | 7851 +++++++++++++++++ package.json | 44 + .../snom/AndroidFunctionalTest.groovy | 106 + .../snom/BasePluginFunctionalTest.groovy | 102 + .../snom/ExtensionFunctionalTest.groovy | 242 + .../snom/MultiProjectFunctionalTest.groovy | 152 + .../spotbugs/snom/ReportFunctionalTest.groovy | 419 + .../snom/StandardFunctionalTest.groovy | 380 + .../github/spotbugs/snom/Confidence.groovy | 69 + .../com/github/spotbugs/snom/Effort.groovy | 54 + .../spotbugs/snom/SpotBugsBasePlugin.java | 126 + .../spotbugs/snom/SpotBugsExtension.groovy | 197 + .../github/spotbugs/snom/SpotBugsPlugin.java | 47 + .../github/spotbugs/snom/SpotBugsReport.java | 141 + .../github/spotbugs/snom/SpotBugsTask.groovy | 400 + .../snom/internal/SpotBugsHtmlReport.java | 101 + .../snom/internal/SpotBugsRunner.java | 135 + .../internal/SpotBugsRunnerForJavaExec.java | 59 + .../internal/SpotBugsRunnerForWorker.java | 107 + .../snom/internal/SpotBugsTaskFactory.java | 93 + .../snom/internal/SpotBugsTextReport.java | 49 + .../snom/internal/SpotBugsXmlReport.java | 49 + .../spotbugs/snom/internal/package-info.java | 19 + .../github/spotbugs/snom/package-info.java | 21 + .../github/spotbugs/SpotBugsExtension.java | 313 - .../com/github/spotbugs/SpotBugsPlugin.java | 209 - .../com/github/spotbugs/SpotBugsReports.java | 46 - .../com/github/spotbugs/SpotBugsTask.java | 728 -- .../github/spotbugs/SpotBugsXmlReport.java | 32 - .../internal/SpotBugsHtmlReportImpl.java | 60 - .../internal/SpotBugsReportsImpl.java | 48 - .../internal/SpotBugsReportsInternal.java | 17 - .../spotbugs/SpotBugsClasspathValidator.java | 45 - .../internal/spotbugs/SpotBugsExecutor.java | 37 - .../internal/spotbugs/SpotBugsResult.java | 38 - .../internal/spotbugs/SpotBugsSpec.java | 43 - .../spotbugs/SpotBugsSpecBuilder.java | 291 - .../internal/spotbugs/SpotBugsWorker.java | 7 - .../spotbugs/SpotBugsWorkerManager.java | 29 - .../spotbugs/SpotBugsXmlReportImpl.java | 26 - .../com.github.spotbugs.properties | 1 - src/test/java/com/github/spotbugs/Bar.groovy | 11 - src/test/java/com/github/spotbugs/Foo.java | 9 - .../java/com/github/spotbugs/FooTest.groovy | 7 - .../com/github/spotbugs/HtmlReportTest.java | 55 - .../java/com/github/spotbugs/Issue31Test.java | 59 - .../com/github/spotbugs/Issue423Test.java | 65 - .../com/github/spotbugs/Issue440Test.java | 61 - .../java/com/github/spotbugs/Issue54Test.java | 65 - .../spotbugs/KotlinBuildScriptTest.java | 74 - .../MultipleBuildOutputSourceDirsTest.java | 130 - .../spotbugs/MultipleClassDirsTest.java | 61 - .../spotbugs/SourceAnalysisProperty.java | 33 - .../spotbugs/SourceAnalysisPropertyTest.java | 57 - .../github/spotbugs/SpotBugsPluginTest.java | 167 - .../spotbugs/snom/SpotBugsPluginTest.java | 53 + src/test/resources/HtmlReportTest.gradle | 17 - src/test/resources/Issue31.gradle | 14 - src/test/resources/Issue423.gradle | 14 - src/test/resources/Issue440.gradle | 8 - src/test/resources/Issue54.gradle | 13 - .../resources/KotlinBuildScript.gradle.kts | 11 - ...MultipleBuildOutputSourceDirsGroovy.gradle | 12 - .../MultipleBuildOutputSourceDirsScala.gradle | 20 - src/test/resources/MultipleClassDirs.gradle | 9 - .../resources/SourceAnalysisProperty.gradle | 16 - src/test/resources/SpotBugsPlugin.gradle | 9 - 106 files changed, 12091 insertions(+), 3364 deletions(-) create mode 100644 .githooks/.gitignore create mode 100755 .githooks/post-checkout create mode 100644 .github/CONTRIBUTING.md create mode 100644 .github/FUNDING.yml create mode 100644 .github/auto-merge.yml create mode 100644 .github/issuehunt-shield-v1.svg create mode 100644 .github/workflows/gradle.yml create mode 100644 .github/workflows/javadoc.yml create mode 100644 .idea/compiler.xml create mode 100644 .idea/google-java-format.xml create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/jarRepositories.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/spotbugs-gradle-plugin-v2.iml create mode 100644 .idea/vcs.xml create mode 100644 .nvmrc delete mode 100644 CHANGELOG.md delete mode 100644 RELEASE_PROCEDURE.md create mode 100644 commitlint.config.js create mode 100644 gradle/HEADER.txt delete mode 100644 gradle/checkstyle.gradle delete mode 100644 gradle/checkstyle.xml delete mode 100644 gradle/deploy.gradle create mode 100644 gradle/errorprone.gradle create mode 100644 gradle/functional-test.gradle delete mode 100644 gradle/jacoco.gradle delete mode 100644 gradle/java.gradle create mode 100644 gradle/publish.gradle delete mode 100644 gradle/sonar.gradle create mode 100755 gradle/spotless.sh create mode 100644 gradle/test.gradle create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 src/functionalTest/groovy/com/github/spotbugs/snom/AndroidFunctionalTest.groovy create mode 100644 src/functionalTest/groovy/com/github/spotbugs/snom/BasePluginFunctionalTest.groovy create mode 100644 src/functionalTest/groovy/com/github/spotbugs/snom/ExtensionFunctionalTest.groovy create mode 100644 src/functionalTest/groovy/com/github/spotbugs/snom/MultiProjectFunctionalTest.groovy create mode 100644 src/functionalTest/groovy/com/github/spotbugs/snom/ReportFunctionalTest.groovy create mode 100644 src/functionalTest/groovy/com/github/spotbugs/snom/StandardFunctionalTest.groovy create mode 100644 src/main/groovy/com/github/spotbugs/snom/Confidence.groovy create mode 100644 src/main/groovy/com/github/spotbugs/snom/Effort.groovy create mode 100644 src/main/groovy/com/github/spotbugs/snom/SpotBugsBasePlugin.java create mode 100644 src/main/groovy/com/github/spotbugs/snom/SpotBugsExtension.groovy create mode 100644 src/main/groovy/com/github/spotbugs/snom/SpotBugsPlugin.java create mode 100644 src/main/groovy/com/github/spotbugs/snom/SpotBugsReport.java create mode 100644 src/main/groovy/com/github/spotbugs/snom/SpotBugsTask.groovy create mode 100644 src/main/groovy/com/github/spotbugs/snom/internal/SpotBugsHtmlReport.java create mode 100644 src/main/groovy/com/github/spotbugs/snom/internal/SpotBugsRunner.java create mode 100644 src/main/groovy/com/github/spotbugs/snom/internal/SpotBugsRunnerForJavaExec.java create mode 100644 src/main/groovy/com/github/spotbugs/snom/internal/SpotBugsRunnerForWorker.java create mode 100644 src/main/groovy/com/github/spotbugs/snom/internal/SpotBugsTaskFactory.java create mode 100644 src/main/groovy/com/github/spotbugs/snom/internal/SpotBugsTextReport.java create mode 100644 src/main/groovy/com/github/spotbugs/snom/internal/SpotBugsXmlReport.java create mode 100644 src/main/groovy/com/github/spotbugs/snom/internal/package-info.java create mode 100644 src/main/groovy/com/github/spotbugs/snom/package-info.java delete mode 100644 src/main/java/com/github/spotbugs/SpotBugsExtension.java delete mode 100644 src/main/java/com/github/spotbugs/SpotBugsPlugin.java delete mode 100644 src/main/java/com/github/spotbugs/SpotBugsReports.java delete mode 100644 src/main/java/com/github/spotbugs/SpotBugsTask.java delete mode 100644 src/main/java/com/github/spotbugs/SpotBugsXmlReport.java delete mode 100644 src/main/java/com/github/spotbugs/internal/SpotBugsHtmlReportImpl.java delete mode 100644 src/main/java/com/github/spotbugs/internal/SpotBugsReportsImpl.java delete mode 100644 src/main/java/com/github/spotbugs/internal/SpotBugsReportsInternal.java delete mode 100644 src/main/java/com/github/spotbugs/internal/spotbugs/SpotBugsClasspathValidator.java delete mode 100644 src/main/java/com/github/spotbugs/internal/spotbugs/SpotBugsExecutor.java delete mode 100644 src/main/java/com/github/spotbugs/internal/spotbugs/SpotBugsResult.java delete mode 100644 src/main/java/com/github/spotbugs/internal/spotbugs/SpotBugsSpec.java delete mode 100644 src/main/java/com/github/spotbugs/internal/spotbugs/SpotBugsSpecBuilder.java delete mode 100644 src/main/java/com/github/spotbugs/internal/spotbugs/SpotBugsWorker.java delete mode 100644 src/main/java/com/github/spotbugs/internal/spotbugs/SpotBugsWorkerManager.java delete mode 100644 src/main/java/com/github/spotbugs/internal/spotbugs/SpotBugsXmlReportImpl.java delete mode 100644 src/main/resources/META-INF/gradle-plugins/com.github.spotbugs.properties delete mode 100644 src/test/java/com/github/spotbugs/Bar.groovy delete mode 100644 src/test/java/com/github/spotbugs/Foo.java delete mode 100644 src/test/java/com/github/spotbugs/FooTest.groovy delete mode 100644 src/test/java/com/github/spotbugs/HtmlReportTest.java delete mode 100644 src/test/java/com/github/spotbugs/Issue31Test.java delete mode 100644 src/test/java/com/github/spotbugs/Issue423Test.java delete mode 100644 src/test/java/com/github/spotbugs/Issue440Test.java delete mode 100644 src/test/java/com/github/spotbugs/Issue54Test.java delete mode 100644 src/test/java/com/github/spotbugs/KotlinBuildScriptTest.java delete mode 100644 src/test/java/com/github/spotbugs/MultipleBuildOutputSourceDirsTest.java delete mode 100644 src/test/java/com/github/spotbugs/MultipleClassDirsTest.java delete mode 100644 src/test/java/com/github/spotbugs/SourceAnalysisProperty.java delete mode 100644 src/test/java/com/github/spotbugs/SourceAnalysisPropertyTest.java delete mode 100644 src/test/java/com/github/spotbugs/SpotBugsPluginTest.java create mode 100644 src/test/java/com/github/spotbugs/snom/SpotBugsPluginTest.java delete mode 100644 src/test/resources/HtmlReportTest.gradle delete mode 100644 src/test/resources/Issue31.gradle delete mode 100644 src/test/resources/Issue423.gradle delete mode 100644 src/test/resources/Issue440.gradle delete mode 100644 src/test/resources/Issue54.gradle delete mode 100644 src/test/resources/KotlinBuildScript.gradle.kts delete mode 100644 src/test/resources/MultipleBuildOutputSourceDirsGroovy.gradle delete mode 100644 src/test/resources/MultipleBuildOutputSourceDirsScala.gradle delete mode 100644 src/test/resources/MultipleClassDirs.gradle delete mode 100644 src/test/resources/SourceAnalysisProperty.gradle delete mode 100644 src/test/resources/SpotBugsPlugin.gradle diff --git a/.githooks/.gitignore b/.githooks/.gitignore new file mode 100644 index 00000000..f41933f0 --- /dev/null +++ b/.githooks/.gitignore @@ -0,0 +1,20 @@ +applypatch-msg +commit-msg +post-applypatch +post-commit +post-merge +post-receive +post-rewrite +post-update +pre-applypatch +pre-auto-gc +pre-commit +pre-merge-commit +pre-push +pre-rebase +pre-receive +prepare-commit-msg +push-to-checkout +sendemail-validate +update +husky.* diff --git a/.githooks/post-checkout b/.githooks/post-checkout new file mode 100755 index 00000000..551f042d --- /dev/null +++ b/.githooks/post-checkout @@ -0,0 +1,23 @@ +#!/bin/sh + +# This script installs the development toolchain runs on node.js (commitlint, husky, prettier, etc.). +# It helps Java engineers to set up full development toolchain seamless. +# +# Gradle plugin (ghooks.gradle) will install this git-hook script. +# We use `post-checkout` because `pre-commit` is used by husky to lint code, and +# `post-clone` is still unofficial so we have no other hook runs before the commit. + +set -e + +if [ ! -d "node_modules" ] +then + if [ -x "$(command -v yarn)" ] + then + echo "🔍🐛 node_modules directory not found, running `yarn install` to install the dev toolchain..." + yarn install + echo "🔍🐛 The dev toolchain has been installed." + else + echo "🔍🐛 The yarn command not found. Please install it to keep your commit clean:" + echo "🔍🐛 https://yarnpkg.com/en/docs/install" + fi +fi diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 00000000..cee1e01e --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,40 @@ +# Contributing Guideline + +## How to hack this project + +Make sure you have Java 11+, Node.js 12+ and NPM on your `PATH`. + +Before you start hacking, run `npm install` once to install development toolchain +to follow [the Conventional Commits](https://conventionalcommits.org/). + +To build the implementation and test, run `./gradlew` then it runs all necessary formatter, compile and test. + +## How to use latest plugin in your project + +To test your changes, you need to build and install the plugin by your own. + +To install the plugin into your Maven Local Repository, add `apply plugin: 'maven-publish'` to `build.gradle` and run `./gradlew publishToMavenLocal`. Then you can use the installed plugin like below: + +```groovy +buildscript { + repositories { + maven { + url "https://plugins.gradle.org/m2/" + } + mavenLocal() + } + dependencies { + classpath "com.github.spotbugs.snom:spotbugs-gradle-plugin:(YOUR_VERSION)" + } +} + +apply plugin: "com.github.spotbugs.snom" +``` + +## Before reporting a problem + +When you find problems and want to share with the community, consider to add some JUnit test cases to reproduce. +Just two steps to follow: + +1. Create a [minimum and complete](http://stackoverflow.com/help/mcve) project, and reproduce it by [functional testing](https://guides.gradle.org/testing-gradle-plugins/). The test code is located in `src/functionalTest` directory. +2. Confirm that `./gradlew clean build` fails by the newly added test case. diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..04196e3c --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: [KengoTODA] diff --git a/.github/auto-merge.yml b/.github/auto-merge.yml new file mode 100644 index 00000000..32b1adbe --- /dev/null +++ b/.github/auto-merge.yml @@ -0,0 +1,6 @@ +minApprovals: + NONE: 0 +requiredLabels: + - dependencies +updateBranch: true +mergeMethod: rebase diff --git a/.github/issuehunt-shield-v1.svg b/.github/issuehunt-shield-v1.svg new file mode 100644 index 00000000..64c30905 --- /dev/null +++ b/.github/issuehunt-shield-v1.svg @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml new file mode 100644 index 00000000..dc390c55 --- /dev/null +++ b/.github/workflows/gradle.yml @@ -0,0 +1,63 @@ +name: Java CI + +on: + push: + branches: + - master + pull_request: + branches: + - master + +jobs: + build: + + runs-on: ubuntu-latest + strategy: + matrix: + gradle: ['5.6', '6.0', '6.1', '6.2'] + steps: + - uses: actions/checkout@722adc6 + with: + fetch-depth: 0 + - name: Set up JDK 11 + uses: actions/setup-java@081536e + with: + java-version: 11 + - name: Set up Node.js 12 + uses: actions/setup-node@8de2f9f + with: + node-version: 12 + - uses: actions/cache@cffae95 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} + restore-keys: | + ${{ runner.os }}-gradle- + - name: Gradle Wrapper Validation + uses: gradle/wrapper-validation-action@v1 + - name: Build with Gradle + run: ./gradlew build --no-daemon -Dsnom.test.functional.gradle=${{ matrix.gradle }} + - name: Run Semantic Release + run: | + echo "gradle.publish.key=${{ secrets.GRADLE_PUBLISH_KEY }}" > ~/.gradle/gradle.properties + echo "gradle.publish.secret=${{ secrets.GRADLE_PUBLISH_SECRET }}" >> ~/.gradle/gradle.properties + rm -rf build/libs/*.jar + npm ci + npm run semantic-release + if: matrix.gradle == '6.0' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Run SonarQube Scanner + run: | + if [ "$SONAR_LOGIN" != "" ]; then + ./gradlew sonarqube -Dsonar.login=$SONAR_LOGIN --no-daemon + fi + if: matrix.gradle == '6.0' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_LOGIN: ${{ secrets.SONAR_LOGIN }} + - uses: actions/upload-artifact@3446296 + if: always() + with: + name: reports + path: build/reports diff --git a/.github/workflows/javadoc.yml b/.github/workflows/javadoc.yml new file mode 100644 index 00000000..dec1f070 --- /dev/null +++ b/.github/workflows/javadoc.yml @@ -0,0 +1,31 @@ +name: Javadoc +on: + push: + branches: + - master +jobs: + javadoc: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@af513c7 + - name: Set up JDK 11 + uses: actions/setup-java@081536e + with: + java-version: 11 + - name: Set up Node.js 12 + uses: actions/setup-node@8de2f9f + with: + node-version: 12 + - name: Generate Groovydoc + run: ./gradlew groovydoc + - name: Prepare to Deploy + run: | + npm ci + rm -f .git/hooks/commit-msg + - name: Deploy + uses: JamesIves/github-pages-deploy-action@c74c1d2 + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BRANCH: gh-pages + FOLDER: build/docs/groovydoc/ diff --git a/.gitignore b/.gitignore index f6206a94..dc96d495 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,328 @@ src/main/resources/spotbugs-gradle-plugin.properties -build -.gradle + +# Created by https://www.gitignore.io/api/linux,gradle,eclipse,windows,jetbrains,node +# Edit at https://www.gitignore.io/?templates=linux,gradle,eclipse,windows,jetbrains,node + +### Eclipse ### +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath +.recommenders + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# PyDev specific (Python IDE for Eclipse) +*.pydevproject + +# CDT-specific (C/C++ Development Tooling) +.cproject + +# CDT- autotools +.autotools + +# Java annotation processor (APT) +.factorypath + +# PDT-specific (PHP Development Tools) +.buildpath + +# sbteclipse plugin +.target + +# Tern plugin +.tern-project + +# TeXlipse plugin +.texlipse + +# STS (Spring Tool Suite) +.springBeans + +# Code Recommenders +.recommenders/ + +# Annotation Processing +.apt_generated/ + +# Scala IDE specific (Scala & Java development for Eclipse) +.cache-main +.scala_dependencies +.worksheet + +### Eclipse Patch ### +# Eclipse Core .project + +# JDT-specific (Eclipse Java Development Tools) .classpath -.settings -/bin/ -.idea/ -*.iml + +# Annotation Processing +.apt_generated + +.sts4-cache/ + +### JetBrains ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### JetBrains Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +.idea/**/sonarlint/ + +# SonarQube Plugin +.idea/**/sonarIssues.xml + +# Markdown Navigator plugin +.idea/**/markdown-navigator.xml +.idea/**/markdown-navigator/ + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### Node ### +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# next.js build output +.next + +# nuxt.js build output +.nuxt + +# rollup.js default build output +dist/ + +# Uncomment the public line if your project uses Gatsby +# https://nextjs.org/blog/next-9-1#public-directory-support +# https://create-react-app.dev/docs/using-the-public-folder/#docsNav +# public + +# Storybook build outputs +.out +.storybook-out + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# Temporary folders +temp/ + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +### Gradle ### +.gradle +build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar + +# Cache of project +.gradletasknamecache + +# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 +# gradle/wrapper/gradle-wrapper.properties + +### Gradle Patch ### +**/build/ + +# End of https://www.gitignore.io/api/linux,gradle,eclipse,windows,jetbrains,node diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 00000000..cf7d3df9 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/google-java-format.xml b/.idea/google-java-format.xml new file mode 100644 index 00000000..8b57f452 --- /dev/null +++ b/.idea/google-java-format.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 00000000..2377d1ec --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 00000000..0380d8d3 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 00000000..feed7233 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/spotbugs-gradle-plugin-v2.iml b/.idea/spotbugs-gradle-plugin-v2.iml new file mode 100644 index 00000000..d6ebd480 --- /dev/null +++ b/.idea/spotbugs-gradle-plugin-v2.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 00000000..35eb1ddf --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000..cd08f2d6 --- /dev/null +++ b/.nvmrc @@ -0,0 +1,4 @@ +12 + +# semantic-release 4.0 recommends to use 10 or above +# https://github.com/commitizen/cz-cli/pull/649 diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 1b082175..00000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,167 +0,0 @@ - -# Changelog - -This is the changelog for SpotBugs Gradle Plugin. This follows [Keep a Changelog v1.0.0](http://keepachangelog.com/en/1.0.0/). - -Currently the versioning policy of this project follows [Semantic Versioning](http://semver.org/) from version 1.6.0. - -## Unreleased - 2019-??-?? - -### Fixed - -* Deprecation warning in Gradle 6 ([#171](https://github.com/spotbugs/spotbugs-gradle-plugin/issues/171)) - -## 3.0.0 - 2019-11-14 - -### Added - -* Gradle 6.1 support ([#174](https://github.com/spotbugs/spotbugs-gradle-plugin/issues/174)) - -### Removed - -* Gradle 5.1 support ([#174](https://github.com/spotbugs/spotbugs-gradle-plugin/issues/174)) - -## 2.0.1 - 2019-10-16 - -### Fixed - -* Avoid needless task creation (#165) - -## 2.0.0 - 2019-05-13 - -### Removed - -* Gradle 5.0 support - -## 1.7.1 - 2019-03-14 - -### Fixed - -* Treat `projectName` and `release` as task input ([#131](https://github.com/spotbugs/spotbugs-gradle-plugin/issues/131)) - -## 1.7.0 - 2019-03-14 - -### Added - -* Add `-projectName` option ([#111](https://github.com/spotbugs/spotbugs-gradle-plugin/issues/111)) -* Add `-release` option ([#111](https://github.com/spotbugs/spotbugs-gradle-plugin/issues/111)) -* Add `setStylesheet(String)` that accepts relative path from the root of `spotbugs.jar` ([#107](https://github.com/spotbugs/spotbugs-gradle-plugin/issues/107)) - -## 1.6.11 - 2019-03-10 - -### Changed - -* Use SpotBugs 3.1.12 by default -* Upgrade SLF4J to 1.8.0-beta4 - -## 1.6.10 - 2019-02-18 - -### Fixed - -* "Trying to add already registered factory" problem reported as [a spotbugs issue](https://github.com/spotbugs/spotbugs/issues/819) -* Result caching works across checkouts. Previously it was using absolute paths and therefore didn't work. ([#96](https://github.com/spotbugs/spotbugs-gradle-plugin/pull/96)) -* Support text type bug report ([#31](https://github.com/spotbugs/spotbugs-gradle-plugin/issues/31)) - -### Removed - -* Usage of worker API introduced at [#57](https://github.com/spotbugs/spotbugs-gradle-plugin/issues/57) -* Drop support for Gradle 4, that causes [SLF4J related problem](https://github.com/gradle/gradle/issues/2657) - -### Changed - -* Use SpotBugs 3.1.11 by default - -## 1.6.9 - 2019-01-04 - -### Fixed - -* `classes` filtering that was broken at 1.6.2 ([#54](https://github.com/spotbugs/spotbugs-gradle-plugin/issues/54)) - -## 1.6.8 - 2018-12-21 - -### Changed - -* Use SpotBugs 3.1.10 by default - -## 1.6.7 - 2018-12-18 - -### Changed - -* Keep track of top-level source set folders [#59](https://github.com/spotbugs/spotbugs-gradle-plugin/pull/59) - -### Fixed - -* Analyze runtime classpath instead of compile classpath. [#62](https://github.com/spotbugs/spotbugs-gradle-plugin/issues/62) - -## 1.6.6 - 2018-12-08 - -## Fixed - -* Prevent NPE in unexpected situations where no reports are enabled, despite xml being set by default using convention mapping (See [#61](https://github.com/spotbugs/spotbugs-gradle-plugin/issues/61), [#68](https://github.com/spotbugs/spotbugs-gradle-plugin/issues/68)) - -## 1.6.5 - 2018-10-17 - -### Changed - -* Replace usage of internal Gradle APIs with supported [Worker API](https://guides.gradle.org/using-the-worker-api/). [#58](https://github.com/spotbugs/spotbugs-gradle-plugin/pull/58) - -## 1.6.4 - 2018-09-26 - -### Changed - -* Use SpotBugs 3.1.7 by default -* Replace usage of internal class ClosureBackedAction [#51](https://github.com/spotbugs/spotbugs-gradle-plugin/pull/51) - -## 1.6.3 - 2018-09-08 - -* Use SpotBugs 3.1.6 -* Added support for passing JVM arguments to the JavaExecHandleBuilder when creating a SpotBugsTask. -* Support Gradle 4.10 that cause problem with problematic method reference. ([#40](https://github.com/spotbugs/spotbugs-gradle-plugin/pull/40)) - -## 1.6.2 - 2018-05-23 - -* Use SpotBugs 3.1.3 -* Add `showProgress` option to task mapping. -* Added a minor fix to handle multiple output source directories. With the release of gradle 4.0 the default location of classes changed from "build/classes/main" -> "build/{java, groovy, scala}/main". This caused a bug where the plugin would ignore any classes compiled which were not located within "build/classes/" or for clean groovy/scala projects the plugin would outright fail to perform an analysis due to NO-SOURCE.([#12](https://github.com/spotbugs/spotbugs-gradle-plugin/pull/12)) -* Support Gradle 4.8 [#22](https://github.com/spotbugs/spotbugs-gradle-plugin/pull/22) - -## 1.6.1 - 2018-02-25 - -* Use SpotBugs 3.1.2 -* Fixed "loud output" [#506](https://github.com/spotbugs/spotbugs/issues/506) by adding an option to show progress and disabling it by default, matching the behaviour of the FindBugs Gradle Plugin - -## 1.6.0 - 2017-10-25 - -* Use SpotBugs 3.1.0 - -## 1.5 - 2017-10-14 - -* Use SpotBugs 3.1.0-RC7 -* Make build failed when user uses unsupported Gradle version ([#357](https://github.com/spotbugs/spotbugs/issues/357)) -* Make error message human readable ([#428](https://github.com/spotbugs/spotbugs/pull/428)) -* Fix missing dependency on compile task ([#440](https://github.com/spotbugs/spotbugs/issues/440)) - -## 1.4 - 2017-09-25 - -* Use SpotBugs 3.1.0-RC6 -* Fix "Cannot convert the provided notation to a File or URI: classesDirs" error ([#320](https://github.com/spotbugs/spotbugs/issues/320)) -* Support working with Android Gradle Plugin 2.3 ([#256](https://github.com/spotbugs/spotbugs/issues/256)) - -## 1.3 - 2017-08-16 [YANKED] - -* Use SpotBugs 3.1.0-RC5 -* Stop using [single class directory](https://docs.gradle.org/4.0.2/release-notes.html#multiple-class-directories-for-a-single-source-set) to prepare for Gradle v5 ([#299](https://github.com/spotbugs/spotbugs/issues/299)) -* Print 'SpotBugs' instead of 'FindBugs' ([#291](https://github.com/spotbugs/spotbugs/issues/291)) - -## 1.2 - 2017-07-21 - -* Use SpotBugs 3.1.0-RC4 -* Fixed [#214](https://github.com/spotbugs/spotbugs/issues/214) - -## 1.1 - 2017-06-10 - -* Use SpotBugs 3.1.0-RC2 - -## 1.0 - 2017-05-16 - -* First release which uses FindBugs 3.0.1 diff --git a/README.md b/README.md index 60423cef..028e0d49 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,107 @@ -# SpotBugs Gradle Plugin +# Newly Organized SpotBugs Gradle Plugin -[![Build Status](https://travis-ci.org/spotbugs/spotbugs-gradle-plugin.svg?branch=master)](https://travis-ci.org/spotbugs/spotbugs-gradle-plugin) +This is the official Gradle Plugin to run SpotBugs on Java and Android project. + +![](https://github.com/spotbugs/spotbugs-gradle-plugin/workflows/Java%20CI/badge.svg) [![Coverage Status](https://sonarcloud.io/api/project_badges/measure?project=com.github.spotbugs.gradle&metric=coverage)](https://sonarcloud.io/component_measures?id=com.github.spotbugs.gradle&metric=coverage) [![Debt](https://sonarcloud.io/api/project_badges/measure?project=com.github.spotbugs.gradle&metric=sqale_index)](https://sonarcloud.io/component_measures/domain/Maintainability?id=com.github.spotbugs.gradle) +[![](https://img.shields.io/badge/groovydoc-latest-blightgreen?logo=groovy)](https://spotbugs-gradle-plugin.netlify.com/com/github/spotbugs/snom/package-summary.html) +[![Issue Hunt](./.github/issuehunt-shield-v1.svg)](https://issuehunt.io/r/spotbugs/spotbugs-gradle-plugin) + +## Goal + +This Gradle plugin is designed to solve the following problems in the legacy plugin: + +- [x] Remove any dependency on the Gradle's internal API +- [x] Solve mutability problem for the build contains multiple projects and/or sourceSet +- [x] Native Support for [the Parallel Build](https://guides.gradle.org/using-the-worker-api/) +- [ ] Native Support for [the Android project](https://developer.android.com/studio/build/gradle-tips) +- [x] Missing user document about how to use extension and task + +## Usage + +### Apply to your project + +Apply the plugin to your project. +Refer [the Gradle Plugin portal](https://plugins.gradle.org/plugin/com.github.spotbugs) about the detail of installation procedure. + +### Configure SpotBugs Plugin + +Configure `spotbugs` extension to configure the behaviour of tasks: + +```groovy +spotbugs { + ignoreFailures = false + showProgress = true + effort = 'default' + reportLevel = 'default' + visitors = [ 'FindSqlInjection', 'SwitchFallthrough' ] + omitVisitors = [ 'FindNonShortCircuit' ] + reportsDir = file("$buildDir/spotbugs") + includeFilter = file("include.xml") + excludeFilter = file("exclude.xml") + onlyAnalyze = [ 'com.foobar.MyClass', 'com.foobar.mypkg.*' ] + maxHeapSize = '1g' + extraArgs = [ '-nested:false' ] + jvmArgs = [ '-Duser.language=ja' ] +} +``` + +Configure `spotbugsPlugin` to apply any SpotBugs plugin: + +```groovy +dependencies { + spotbugsPlugins 'com.h3xstream.findsecbugs:findsecbugs-plugin:1.7.1' +} +``` + +Configure `spotbugs` to choose your favorite SpotBugs version: + +```groovy +dependencies { + spotbugs 'com.github.spotbugs:spotbugs:4.0.0' +} +``` + +### Apply to Java project + +Apply this plugin with [the `java` plugin](https://docs.gradle.org/current/userguide/java_plugin.html) to your project, +then [`SpotBugsTask`](https://spotbugs-gradle-plugin.netlify.com/com/github/spotbugs/snom/spotbugstask) will be generated for each existing sourceSet. + +If you want to create and configure `SpotBugsTask` by own, apply the base plugin (`com.github.spotbugs-base`) instead, then it won't create tasks automatically. + +### Apply to Android project + +TBU + +### Configure the SpotBugsTask + +Configure [`SpotBugsTask`](https://spotbugs-gradle-plugin.netlify.com/com/github/spotbugs/snom/spotbugstask) directly, +to set task-specific properties. + +```groovy +// Example to configure HTML report +spotbugsMain { + reports { + html { + enabled = true + destination = file("$buildDir/reports/spotbugs/main/spotbugs.html") + stylesheet = 'fancy-hist.xsl' + } + } +} +``` +## SpotBugs version mapping -## License +By default, this Gradle Plugin uses the SpotBugs version listed in this table. -Copyright 2017-2019 the original author or authors. +You can change SpotBugs version by [the `toolVersion` property of the spotbugs extension](https://spotbugs-gradle-plugin.netlify.com/com/github/spotbugs/snom/spotbugsextension#toolVersion) or the `spotbugs` configuration. -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at +|Gradle Plugin|SpotBugs| +|-----:|-----:| +| 4.0.0| 4.0.0| -http://www.apache.org/licenses/LICENSE-2.0 +## Copyright -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. +Copyright © 2019-present SpotBugs Team diff --git a/RELEASE_PROCEDURE.md b/RELEASE_PROCEDURE.md deleted file mode 100644 index ff68ec69..00000000 --- a/RELEASE_PROCEDURE.md +++ /dev/null @@ -1,29 +0,0 @@ -# Release procedure - -When you release fixed version of SpotBugs Gradle Plugin, please follow these procedures. - -## Update version info - -Create a commit to handle following changes: - -* Remove `-SNAPSHOT` from `version` in `build.gradle` -* Replace `Unreleased` with actual version number in `CHANGELOG.md` - -This commit will be tagged with version number. Refer [db979662](https://github.com/spotbugs/spotbugs-gradle-plugin/commit/db9796621629fd6326f8618ddc4660e881a8b396) as example. - -## Prepare for next development - -Create a commit to handle following changes: - -* change `version` in `build.gradle` to SNAPSHOT version -* add `Unreleased - 2019-??-??` into `CHANGELOG.md` - -Refer [ef63f198](https://github.com/spotbugs/spotbugs-gradle-plugin/commit/ef63f1980d75a1999af00b3505667f3932c8c0fa) as example. - -## Create pull request, and merge it with review - -Now you have two commits in your topic branch. Create a pull request from it, and ask other SpotBugs teammates to review. They'll merge and tag your commit. - -## Release to Gradle Plugin Portal - -When we push tag, the build result on Travis CI will be deployed to [Gradle Plugin Portal](https://plugins.gradle.org/). Check [official document](https://plugins.gradle.org/docs/submit) for detail. diff --git a/build.gradle b/build.gradle index 098127ca..01f357ca 100644 --- a/build.gradle +++ b/build.gradle @@ -1,72 +1,61 @@ -plugins{ - id 'groovy' - id 'java-gradle-plugin' - id "com.gradle.plugin-publish" version "0.10.1" - id 'org.sonarqube' version '2.8' - id 'com.diffplug.gradle.spotless' version '3.27.1' +plugins { + id 'groovy' + id 'java-gradle-plugin' + id 'jacoco' + id 'com.gradle.plugin-publish' version '0.10.1' + id 'com.diffplug.gradle.spotless' version '3.27.1' + id 'net.ltgt.errorprone' version '1.1.1' + id 'se.patrikerdes.use-latest-versions' version '0.2.13' + id 'com.github.ben-manes.versions' version '0.27.0' + id 'org.sonarqube' version '2.8' + id 'com.gtramontina.ghooks.gradle' version '1.1.1' } -apply from: "$rootDir/gradle/checkstyle.gradle" -apply from: "$rootDir/gradle/jacoco.gradle" -apply from: "$rootDir/gradle/java.gradle" -apply from: "$rootDir/gradle/sonar.gradle" -apply from: "$rootDir/gradle/deploy.gradle" -apply from: "$rootDir/gradle/spotless.gradle" - -version = '3.0.1-SNAPSHOT' -group = "com.github.spotbugs" -def spotBugsVersion = '3.1.12' -def slf4jVersion = '1.8.0-beta4' sourceCompatibility = 1.8 targetCompatibility = 1.8 +group = 'com.github.spotbugs.snom' repositories { - jcenter() + // To download the Android Gradle Plugin + google() + // To download trove4j required by the Android Gradle Plugin + jcenter() } -dependencies { - implementation gradleApi() - implementation localGroovy() - compileOnly "com.github.spotbugs:spotbugs:${spotBugsVersion}" - - testImplementation gradleTestKit() - testImplementation 'junit:junit:4.13'//, 'org.spockframework:spock-core:1.0-groovy-2.4' +ext { + errorproneVersion = '2.3.4' + spotBugsVersion = '4.0.0' + slf4jVersion = '1.8.0-beta4' + androidGradlePluginVersion = '3.5.3' } -test { - // show test output - testLogging.showStandardStreams = true +dependencies { + errorprone "com.google.errorprone:error_prone_core:${errorproneVersion}" + compileOnly localGroovy() + compileOnly "com.github.spotbugs:spotbugs:${spotBugsVersion}" + compileOnly "com.android.tools.build:gradle:${androidGradlePluginVersion}" + testImplementation 'com.tngtech.archunit:archunit:0.13.1' } -// The configuration example below shows the minimum required properties -// configured to publish your plugin to the plugin portal -pluginBundle { - website = 'https://spotbugs.github.io/' - vcsUrl = 'https://github.com/spotbugs/spotbugs-gradle-plugin' - description = "Performs quality checks on your project's Java source files using SpotBugs and generates reports from these checks" - tags = ['spotbugs', 'findbugs', 'code quality'] - - plugins { - spotbugsPlugin { - id = 'com.github.spotbugs' - displayName = 'SpotBugs Gradle plugin' - } - } +groovydoc { + docTitle 'SpotBugs Gradle Plugin' + link 'https://docs.gradle.org/current/javadoc/', 'org.gradle.api.' + link 'https://docs.oracle.com/en/java/javase/11/docs/api/', 'java.' + link 'https://docs.groovy-lang.org/latest/html/gapi/', 'groovy.', 'org.codehaus.groovy.' } task processVersionFile(type: WriteProperties) { - outputFile file('src/main/resources/spotbugs-gradle-plugin.properties') + outputFile file('src/main/resources/spotbugs-gradle-plugin.properties') - property 'spotbugs-version', spotBugsVersion - property 'slf4j-version', slf4jVersion + property 'slf4j-version', slf4jVersion + property 'spotbugs-version', spotBugsVersion } tasks.processResources.dependsOn processVersionFile -tasks.publishPlugins.doFirst { - if (version.endsWith('-SNAPSHOT')) { - throw new StopExecutionException("Skip publishing Gradle plugin because its version is not stable: ${version}") - } - if (spotBugsVersion.endsWith('-SNAPSHOT')) { - throw new StopExecutionException("Skip publishing Gradle plugin because SpotBugs version is not stable: ${spotBugsVersion}") - } -} +apply from: "$rootDir/gradle/test.gradle" +apply from: "$rootDir/gradle/functional-test.gradle" +apply from: "$rootDir/gradle/spotless.gradle" +apply from: "$rootDir/gradle/errorprone.gradle" +apply from: "$rootDir/gradle/publish.gradle" + +defaultTasks 'spotlessApply', 'build' diff --git a/commitlint.config.js b/commitlint.config.js new file mode 100644 index 00000000..74eda5bf --- /dev/null +++ b/commitlint.config.js @@ -0,0 +1,36 @@ +module.exports = { + parserPreset: 'conventional-changelog-conventionalcommits', + rules: { + 'body-leading-blank': [1, 'always'], + 'footer-leading-blank': [1, 'always'], + 'header-max-length': [2, 'always', 72], + 'scope-case': [2, 'always', 'lower-case'], + 'subject-case': [ + 2, + 'never', + ['sentence-case', 'start-case', 'pascal-case', 'upper-case'] + ], + 'subject-empty': [2, 'never'], + 'subject-full-stop': [2, 'never', '.'], + 'type-case': [2, 'always', 'lower-case'], + 'type-empty': [2, 'never'], + 'type-enum': [ + 2, + 'always', + [ + 'build', + 'chore', + 'ci', + 'docs', + 'feat', + 'fix', + 'improvement', + 'perf', + 'refactor', + 'revert', + 'style', + 'test' + ] + ] + } +}; diff --git a/gradle/HEADER.txt b/gradle/HEADER.txt new file mode 100644 index 00000000..4a2e832b --- /dev/null +++ b/gradle/HEADER.txt @@ -0,0 +1,13 @@ +/* + * Copyright 2019 SpotBugs team + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ \ No newline at end of file diff --git a/gradle/checkstyle.gradle b/gradle/checkstyle.gradle deleted file mode 100644 index bd2c0170..00000000 --- a/gradle/checkstyle.gradle +++ /dev/null @@ -1,10 +0,0 @@ -// Setup checkstyle -apply plugin: 'checkstyle' - -checkstyle { - toolVersion '8.10' - ignoreFailures false - configFile file("$rootDir/gradle/checkstyle.xml") -} - -task checkstyle(dependsOn: [checkstyleMain, checkstyleTest]) diff --git a/gradle/checkstyle.xml b/gradle/checkstyle.xml deleted file mode 100644 index 87abbd35..00000000 --- a/gradle/checkstyle.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/gradle/deploy.gradle b/gradle/deploy.gradle deleted file mode 100644 index 993147c5..00000000 --- a/gradle/deploy.gradle +++ /dev/null @@ -1,47 +0,0 @@ -// see https://central.sonatype.org/pages/gradle.html -// and https://docs.gradle.org/current/userguide/publishing_maven.html - -apply plugin: 'maven-publish' - -task sourcesJar(type: Jar) { - from sourceSets.main.allJava - archiveClassifier = 'sources' -} - -task javadocJar(type: Jar) { - from javadoc - archiveClassifier = 'javadoc' -} - -publishing { - repositories { - maven { - url "https://oss.sonatype.org/content/repositories/snapshots/" - credentials { - username = project.hasProperty('ossrhUsername') ? ossrhUsername : "Unknown user" - password = project.hasProperty('ossrhPassword') ? ossrhPassword : "Unknown password" - } - } - } - publications { - pluginMaven(MavenPublication) { // add config to the publications generated by java-gradle-plugin. https://github.com/gradle/gradle/issues/10384#issuecomment-530347578 - artifact sourcesJar - artifact javadocJar - pom { - description = 'A Gradle plugin for SpotBugs' - url = 'https://github.com/spotbugs/spotbugs-gradle-plugin/' - scm { - connection = 'scm:git:git@github.com:spotbugs/spotbugs-gradle-plugin.git' - developerConnection = 'scm:git:git@github.com:spotbugs/spotbugs-gradle-plugin.git' - url = 'https://github.com/spotbugs/spotbugs-gradle-plugin/' - } - licenses { - license { - name = 'The Apache License, Version 2.0' - url = 'http://www.apache.org/licenses/LICENSE-2.0.txt' - } - } - } - } - } -} diff --git a/gradle/errorprone.gradle b/gradle/errorprone.gradle new file mode 100644 index 00000000..0596c716 --- /dev/null +++ b/gradle/errorprone.gradle @@ -0,0 +1,5 @@ +// disable warnings in generated code by immutables +// https://github.com/google/error-prone/issues/329 +tasks.withType(JavaCompile).configureEach { + options.errorprone.disableWarningsInGeneratedCode = true +} diff --git a/gradle/functional-test.gradle b/gradle/functional-test.gradle new file mode 100644 index 00000000..c0486755 --- /dev/null +++ b/gradle/functional-test.gradle @@ -0,0 +1,32 @@ +configurations { + functionalTestImplementation { + extendsFrom testImplementation + } +} +dependencies { + functionalTestImplementation 'org.spockframework:spock-core:1.3-groovy-2.5' +} + +sourceSets { + functionalTest { + groovy.srcDir file('src/functionalTest/groovy') + resources.srcDir file('src/functionalTest/resources') + compileClasspath += sourceSets.main.output + runtimeClasspath += output + compileClasspath + } +} + +gradlePlugin { + testSourceSets sourceSets.functionalTest +} + +task functionalTest(type: Test) { + description = 'Runs the functional tests.' + group = 'verification' + testClassesDirs = sourceSets.functionalTest.output.classesDirs + classpath = sourceSets.functionalTest.runtimeClasspath + mustRunAfter test + systemProperty 'snom.test.functional.gradle', System.getProperty('snom.test.functional.gradle', gradle.gradleVersion) +} + +check.dependsOn functionalTest diff --git a/gradle/jacoco.gradle b/gradle/jacoco.gradle deleted file mode 100644 index 06167c20..00000000 --- a/gradle/jacoco.gradle +++ /dev/null @@ -1,18 +0,0 @@ -apply plugin: "jacoco" - -jacoco { - toolVersion = "0.8.2" -} - -jacocoTestReport { - reports { - html.enabled = true - } -} - -test { - jacoco { - // https://github.com/gradle/gradle/issues/5184#issuecomment-391982009 - excludes = ['jdk.internal.*'] - } -} diff --git a/gradle/java.gradle b/gradle/java.gradle deleted file mode 100644 index 9b7d6ddc..00000000 --- a/gradle/java.gradle +++ /dev/null @@ -1,8 +0,0 @@ -apply plugin: 'java' - -tasks.withType(JavaCompile) { - options.encoding = 'UTF-8' -} -tasks.withType(Javadoc) { - options.encoding = 'UTF-8' -} \ No newline at end of file diff --git a/gradle/publish.gradle b/gradle/publish.gradle new file mode 100644 index 00000000..9f74b55b --- /dev/null +++ b/gradle/publish.gradle @@ -0,0 +1,29 @@ +// configuration to publish gradle plugin to plugin portal +// https://guides.gradle.org/publishing-plugins-to-gradle-plugin-portal/ + +pluginBundle { + website = 'https://github.com/spotbugs/spotbugs-gradle-plugin' + vcsUrl = 'https://github.com/spotbugs/spotbugs-gradle-plugin' + tags = [ + 'spotbugs', + 'static analysis', + 'code quality' + ] +} + +gradlePlugin { + plugins { + spotbugsGradleBasePlugin { + id = 'com.github.spotbugs-base' + displayName = 'Official SpotBugs Gradle Base Plugin' + description = 'A base Gradle plugin that runs static bytecode analysis by SpotBugs' + implementationClass = 'com.github.spotbugs.snom.SpotBugsBasePlugin' + } + spotbugsGradlePlugin { + id = 'com.github.spotbugs' + displayName = 'Official SpotBugs Gradle Plugin' + description = 'A Gradle plugin that runs static bytecode analysis by SpotBugs' + implementationClass = 'com.github.spotbugs.snom.SpotBugsPlugin' + } + } +} diff --git a/gradle/sonar.gradle b/gradle/sonar.gradle deleted file mode 100644 index b3036ece..00000000 --- a/gradle/sonar.gradle +++ /dev/null @@ -1,10 +0,0 @@ -apply plugin: 'org.sonarqube' - -sonarqube { - properties { - property 'sonar.login', System.env.SONAR_LOGIN - property 'sonar.projectKey', 'com.github.spotbugs.gradle' - property 'sonar.projectName', 'SpotBugs Gradle Plugin' - property 'sonar.projectVersion', rootProject.version - } -} diff --git a/gradle/spotless.gradle b/gradle/spotless.gradle index d36d701d..66a22f6a 100644 --- a/gradle/spotless.gradle +++ b/gradle/spotless.gradle @@ -1,7 +1,21 @@ +// configuration for spotless +// https://github.com/diffplug/spotless/tree/master/plugin-gradle + spotless { - java { - removeUnusedImports() - trimTrailingWhitespace() - indentWithSpaces() - } + java { + licenseHeaderFile 'gradle/HEADER.txt' + removeUnusedImports() + googleJavaFormat() + } + groovy { + licenseHeaderFile 'gradle/HEADER.txt' + target '**/*.groovy' + greclipse() + indentWithSpaces() + } + groovyGradle { + target '**/*.gradle' + greclipse() + indentWithSpaces() + } } diff --git a/gradle/spotless.sh b/gradle/spotless.sh new file mode 100755 index 00000000..6bc75b79 --- /dev/null +++ b/gradle/spotless.sh @@ -0,0 +1,19 @@ +#!/bin/sh +# From https://github.com/diffplug/spotless/issues/178#issuecomment-351638034 + +echo '[git hook] executing gradle spotlessApply before commit' + +# stash any unstaged changes +git stash -q --keep-index + +# run the spotlessCheck with the gradle wrapper +./gradlew spotlessApply --daemon + +# store the last exit code in a variable +RESULT=$? + +# unstash the unstashed changes +git stash pop -q + +# return the './gradlew spotlessApply' exit code +exit $RESULT diff --git a/gradle/test.gradle b/gradle/test.gradle new file mode 100644 index 00000000..48567f68 --- /dev/null +++ b/gradle/test.gradle @@ -0,0 +1,36 @@ +ext { + junitVersion = '5.6.0' +} +dependencies { + testImplementation gradleTestKit() + testImplementation "org.junit.jupiter:junit-jupiter-api:${junitVersion}" + testImplementation "org.junit.jupiter:junit-jupiter-params:${junitVersion}" + testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junitVersion}" +} + +test { + useJUnitPlatform() + maxParallelForks = Runtime.runtime.availableProcessors() +} + +jacoco { + toolVersion = "0.8.5" +} +jacocoTestReport { + reports { + xml { + enabled true + } + } +} +tasks.check.dependsOn 'jacocoTestReport' + +sonarqube { + properties { + property "sonar.projectKey", "com.github.spotbugs.gradle" + property "sonar.organization", "spotbugs" + property "sonar.host.url", "https://sonarcloud.io" + property "sonar.coverage.jacoco.xmlReportPaths", jacocoTestReport.reports.xml.destination + } +} +tasks.sonarqube.mustRunAfter jacocoTestReport diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 457aad0d98108420a977756b7145c93c8910b076..f3d88b1c2faf2fc91d853cd5d4242b5547257070 100644 GIT binary patch delta 32156 zcmY)VV{oNS*su#{qREPFOeVH%+qOBey(YG8+t!M0XJXqnzI#7U?ft#)zpMJH?mvB2 z9mk38YJ?aWhk#O)fq;aK@56}4MMHxH1A~D90|OHRv#san6a4Q>AYM=ojXDU63=_Qw z^VaFs=?B>Vy8#LEzyJ1577P&o?-KQo|L35@A3q4N{{JT>lP#3A{{RESfdB(zNEDLC zOspA02a+<;o7fmRJ4Y)|*ewX6^DVTwGL-~9h0=LrQi~U)r&V_KUy;2a zP9MjS*av)|d8FYghWx?+_f9qqgDvDcp(*1@f8Am@=4@pd5!!P8Tnk@ydDG<-z&i zBr}Z@S~O6i4~#h4y(?{xv#QKd&`6M&6=Hc_!H(>xS}(ZHbDOp1x=;#|hvRbjSF8IF z3ye!1&&gz$Pm_)pol59gG@rV!T~o3wsT-aeP$pw@RjGbSpu%*#u8>!V!rJJPAC#Ha z1JBVCO+AH{%bfywA8#24No;~|>M85^txg#eO%mag_;}ZV3MG&A1jau*!7phz=oP;U zA8fCM$+CLaw&ju$=1}SC+=n`Bb_3b1crjkInH#xSmY*(8&KgP3ZbIkl!Q9)|I&2Uu z`}cu+cQ5Tn9-Ktt|4zi30^Iz*@di`Rbh&oA6v>brvfVj<%+k*(vz)2i0p^+;HiS&B zXsmNBPL#y#<$tMooo)&jdOg=iC07hu59tnYSBI{z^dfluP|_djv;Ut!`2Qlt>IZEl z5fm60DQsfBF3x|Kj0=obUsplX!2Tw1Uag}IW1kmKyutd_57|Bd5Zg@{eJukDF`xyHXCPc z&t__JN>9ZJD0NYBmuGoF9ixH⁣HwUsu~aXiT2}-Fnu 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 z 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�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 delta 29443 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

uV_Wabwfb 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 8" + } + }, + "@samverschueren/stream-to-observable": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz", + "integrity": "sha512-MI4Xx6LHs4Webyvi6EbspgyAb4D2Q2VtnCQ1blOJcoLS6mVa8lNN2rkIy1CVxfTUpoyIbCTkXES1rLXztFD1lg==", + "dev": true, + "requires": { + "any-observable": "^0.3.0" + } + }, + "@semantic-release/commit-analyzer": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-8.0.1.tgz", + "integrity": "sha512-5bJma/oB7B4MtwUkZC2Bf7O1MHfi4gWe4mA+MIQ3lsEV0b422Bvl1z5HRpplDnMLHH3EXMoRdEng6Ds5wUqA3A==", + "dev": true, + "requires": { + "conventional-changelog-angular": "^5.0.0", + "conventional-commits-filter": "^2.0.0", + "conventional-commits-parser": "^3.0.7", + "debug": "^4.0.0", + "import-from": "^3.0.0", + "lodash": "^4.17.4", + "micromatch": "^4.0.2" + } + }, + "@semantic-release/error": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-2.2.0.tgz", + "integrity": "sha512-9Tj/qn+y2j+sjCI3Jd+qseGtHjOAeg7dU2/lVcqIQ9TV3QDaDXDYXcoOHU+7o2Hwh8L8ymL4gfuO7KxDs3q2zg==", + "dev": true + }, + "@semantic-release/github": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-7.0.3.tgz", + "integrity": "sha512-4Y2nqruKHsdoayq/H/lMWudONXHLbYtSBDZPktoTrvdJZNQkLhjnxCwDUTKo8G29aI81RuoYKUHv6GSgyJDtGQ==", + "dev": true, + "requires": { + "@octokit/rest": "^16.43.0", + "@semantic-release/error": "^2.2.0", + "aggregate-error": "^3.0.0", + "bottleneck": "^2.18.1", + "debug": "^4.0.0", + "dir-glob": "^3.0.0", + "fs-extra": "^8.0.0", + "globby": "^11.0.0", + "http-proxy-agent": "^4.0.0", + "https-proxy-agent": "^5.0.0", + "issue-parser": "^6.0.0", + "lodash": "^4.17.4", + "mime": "^2.4.3", + "p-filter": "^2.0.0", + "p-retry": "^4.0.0", + "url-join": "^4.0.0" + } + }, + "@semantic-release/npm": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-7.0.3.tgz", + "integrity": "sha512-3wOXMtAdJkaAnW5183iSmWSimtUmOx7m6g/DWPYRs2Gq6iyB+ztMmhgwbn6luNcM9t6pGbgHvRPEXpWkygMxCA==", + "dev": true, + "requires": { + "@semantic-release/error": "^2.2.0", + "aggregate-error": "^3.0.0", + "execa": "^4.0.0", + "fs-extra": "^8.0.0", + "lodash": "^4.17.15", + "nerf-dart": "^1.0.0", + "normalize-url": "^5.0.0", + "npm": "^6.10.3", + "rc": "^1.2.8", + "read-pkg": "^5.0.0", + "registry-auth-token": "^4.0.0", + "semver": "^7.1.2", + "tempy": "^0.4.0" + }, + "dependencies": { + "parse-json": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", + "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1", + "lines-and-columns": "^1.1.6" + } + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + } + }, + "semver": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.1.3.tgz", + "integrity": "sha512-ekM0zfiA9SCBlsKa2X1hxyxiI4L3B6EbVJkkdgQXnSEEaHlGdvyodMruTiulSRWMMB4NeIuYNMC9rTKTz97GxA==", + "dev": true + } + } + }, + "@semantic-release/release-notes-generator": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-9.0.0.tgz", + "integrity": "sha512-fhMUC5gAYZ1tNUDarB85PdY2xQtrPJH1wkXfvLJuhNa3BLn2geMRwdX+BtyHUloQj5KXVB8OXIq5xXz0IGvhYA==", + "dev": true, + "requires": { + "conventional-changelog-angular": "^5.0.0", + "conventional-changelog-writer": "^4.0.0", + "conventional-commits-filter": "^2.0.0", + "conventional-commits-parser": "^3.0.0", + "debug": "^4.0.0", + "get-stream": "^5.0.0", + "import-from": "^3.0.0", + "into-stream": "^5.0.0", + "lodash": "^4.17.4", + "read-pkg-up": "^7.0.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", + "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "parse-json": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", + "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1", + "lines-and-columns": "^1.1.6" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true + } + } + }, + "read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "requires": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + } + } + }, + "@tootallnate/once": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.0.0.tgz", + "integrity": "sha512-KYyTT/T6ALPkIRd2Ge080X/BsXvy9O0hcWTtMWkPvwAwF99+vn6Dv4GzrFT/Nn1LePr+FFDbRXXlqmsy9lw2zA==", + "dev": true + }, + "@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", + "dev": true + }, + "@types/node": { + "version": "13.7.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.7.1.tgz", + "integrity": "sha512-Zq8gcQGmn4txQEJeiXo/KiLpon8TzAl0kmKH4zdWctPj05nWwp1ClMdAVEloqrQKfaC48PNLdgN/aVaLqUrluA==", + "dev": true + }, + "@types/normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", + "dev": true + }, + "@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "dev": true + }, + "@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true + }, + "JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + } + }, + "agent-base": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.0.tgz", + "integrity": "sha512-j1Q7cSCqN+AwrmDd+pzgqc0/NpC655x2bUf5ZjRIO77DcNBFmh+OgRNzF6OKdCC9RSCb19fGd99+bhXFdkRNqw==", + "dev": true, + "requires": { + "debug": "4" + } + }, + "aggregate-error": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz", + "integrity": "sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "dependencies": { + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + } + } + }, + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "ansicolors": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz", + "integrity": "sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk=", + "dev": true + }, + "any-observable": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/any-observable/-/any-observable-0.3.0.tgz", + "integrity": "sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog==", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "argv-formatter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/argv-formatter/-/argv-formatter-1.0.0.tgz", + "integrity": "sha1-oMoMvCmltz6Dbuvhy/bF4OTrgvk=", + "dev": true + }, + "array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", + "dev": true + }, + "array-ify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", + "integrity": "sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4=", + "dev": true + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "atob-lite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/atob-lite/-/atob-lite-2.0.0.tgz", + "integrity": "sha1-D+9a1G8b16hQLGVyfwNn1e5D1pY=", + "dev": true + }, + "babel-polyfill": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz", + "integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "core-js": "^2.5.0", + "regenerator-runtime": "^0.10.5" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", + "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=", + "dev": true + } + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "dev": true, + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "before-after-hook": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.1.0.tgz", + "integrity": "sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A==", + "dev": true + }, + "bottleneck": { + "version": "2.19.5", + "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", + "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "btoa-lite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/btoa-lite/-/btoa-lite-1.0.0.tgz", + "integrity": "sha1-M3dm2hWAEhD92VbCLpxokaudAzc=", + "dev": true + }, + "caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "dev": true, + "requires": { + "callsites": "^2.0.0" + }, + "dependencies": { + "callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "dev": true + } + } + }, + "caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "dev": true, + "requires": { + "caller-callsite": "^2.0.0" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "camelcase-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-4.2.0.tgz", + "integrity": "sha1-oqpfsa9oh1glnDLBQUJteJI7m3c=", + "dev": true, + "requires": { + "camelcase": "^4.1.0", + "map-obj": "^2.0.0", + "quick-lru": "^1.0.0" + } + }, + "cardinal": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/cardinal/-/cardinal-2.1.1.tgz", + "integrity": "sha1-fMEFXYItISlU0HsIXeolHMe8VQU=", + "dev": true, + "requires": { + "ansicolors": "~0.3.2", + "redeyed": "~2.1.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "cli-table": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz", + "integrity": "sha1-9TsFJmqLGguTSz0IIebi3FkUriM=", + "dev": true, + "requires": { + "colors": "1.0.3" + } + }, + "cli-truncate": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz", + "integrity": "sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ=", + "dev": true, + "requires": { + "slice-ansi": "0.0.4", + "string-width": "^1.0.1" + } + }, + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + } + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", + "dev": true + }, + "commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true + }, + "commitlint": { + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/commitlint/-/commitlint-8.3.5.tgz", + "integrity": "sha512-vsJr4azgWgwQcBtQOJEMUH5m7yzhD6p09dss7XNs4a88ksBtWAHKXoCKaBCt9ISS1yWcxFRUwnNy7zZhjmnXdg==", + "dev": true, + "requires": { + "@commitlint/cli": "^8.3.5", + "read-pkg": "5.2.0", + "resolve-pkg": "2.0.0" + }, + "dependencies": { + "@commitlint/cli": { + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-8.3.5.tgz", + "integrity": "sha512-6+L0vbw55UEdht71pgWOE55SRgb+8OHcEwGDB234VlIBFGK9P2QOBU7MHiYJ5cjdjCQ0rReNrGjOHmJ99jwf0w==", + "dev": true, + "requires": { + "@commitlint/format": "^8.3.4", + "@commitlint/lint": "^8.3.5", + "@commitlint/load": "^8.3.5", + "@commitlint/read": "^8.3.4", + "babel-polyfill": "6.26.0", + "chalk": "2.4.2", + "get-stdin": "7.0.0", + "lodash": "4.17.15", + "meow": "5.0.0", + "resolve-from": "5.0.0", + "resolve-global": "1.0.0" + } + }, + "parse-json": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", + "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1", + "lines-and-columns": "^1.1.6" + } + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + } + } + } + }, + "compare-func": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-1.3.2.tgz", + "integrity": "sha1-md0LpFfh+bxyKxLAjsM+6rMfpkg=", + "dev": true, + "requires": { + "array-ify": "^1.0.0", + "dot-prop": "^3.0.0" + } + }, + "compare-versions": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz", + "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "conventional-changelog-angular": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.6.tgz", + "integrity": "sha512-QDEmLa+7qdhVIv8sFZfVxU1VSyVvnXPsxq8Vam49mKUcO1Z8VTLEJk9uI21uiJUsnmm0I4Hrsdc9TgkOQo9WSA==", + "dev": true, + "requires": { + "compare-func": "^1.3.1", + "q": "^1.5.1" + } + }, + "conventional-changelog-conventionalcommits": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.2.3.tgz", + "integrity": "sha512-atGa+R4vvEhb8N/8v3IoW59gCBJeeFiX6uIbPu876ENAmkMwsenyn0R21kdDHJFLQdy6zW4J6b4xN8KI3b9oww==", + "dev": true, + "requires": { + "compare-func": "^1.3.1", + "lodash": "^4.17.15", + "q": "^1.5.1" + } + }, + "conventional-changelog-writer": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.0.11.tgz", + "integrity": "sha512-g81GQOR392I+57Cw3IyP1f+f42ME6aEkbR+L7v1FBBWolB0xkjKTeCWVguzRrp6UiT1O6gBpJbEy2eq7AnV1rw==", + "dev": true, + "requires": { + "compare-func": "^1.3.1", + "conventional-commits-filter": "^2.0.2", + "dateformat": "^3.0.0", + "handlebars": "^4.4.0", + "json-stringify-safe": "^5.0.1", + "lodash": "^4.17.15", + "meow": "^5.0.0", + "semver": "^6.0.0", + "split": "^1.0.0", + "through2": "^3.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "conventional-commits-filter": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.2.tgz", + "integrity": "sha512-WpGKsMeXfs21m1zIw4s9H5sys2+9JccTzpN6toXtxhpw2VNF2JUXwIakthKBy+LN4DvJm+TzWhxOMWOs1OFCFQ==", + "dev": true, + "requires": { + "lodash.ismatch": "^4.4.0", + "modify-values": "^1.0.0" + } + }, + "conventional-commits-parser": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.0.8.tgz", + "integrity": "sha512-YcBSGkZbYp7d+Cr3NWUeXbPDFUN6g3SaSIzOybi8bjHL5IJ5225OSCxJJ4LgziyEJ7AaJtE9L2/EU6H7Nt/DDQ==", + "dev": true, + "requires": { + "JSONStream": "^1.0.4", + "is-text-path": "^1.0.1", + "lodash": "^4.17.15", + "meow": "^5.0.0", + "split2": "^2.0.0", + "through2": "^3.0.0", + "trim-off-newlines": "^1.0.0" + } + }, + "core-js": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", + "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "dev": true, + "requires": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + }, + "dependencies": { + "import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "dev": true, + "requires": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + } + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true + }, + "currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "dev": true, + "requires": { + "array-find-index": "^1.0.1" + } + }, + "dargs": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/dargs/-/dargs-4.1.0.tgz", + "integrity": "sha1-A6nbtLXC8Tm/FK5T8LiipqhvThc=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "date-fns": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", + "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==", + "dev": true + }, + "dateformat": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", + "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", + "dev": true + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decamelize-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", + "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", + "dev": true, + "requires": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "dependencies": { + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true + } + } + }, + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "dev": true + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, + "deprecation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", + "dev": true + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + }, + "dependencies": { + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + } + } + }, + "dot-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-3.0.0.tgz", + "integrity": "sha1-G3CK8JSknJoOfbyteQq6U52sEXc=", + "dev": true, + "requires": { + "is-obj": "^1.0.0" + } + }, + "duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", + "dev": true, + "requires": { + "readable-stream": "^2.0.2" + } + }, + "elegant-spinner": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz", + "integrity": "sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4=", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "env-ci": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/env-ci/-/env-ci-5.0.1.tgz", + "integrity": "sha512-xXgohoOAFFF1Y3EdsSKP7olyH/DLS6ZD3aglV6mDFAXBqBXLJSsZLrOZdYfDs5mOmgNaP3YYynObzwF3QkC24g==", + "dev": true, + "requires": { + "execa": "^4.0.0", + "java-properties": "^1.0.0" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "execa": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.0.0.tgz", + "integrity": "sha512-JbDUxwV3BoT5ZVXQrSVbAiaXhXUkIwvbhPIwZ0N13kX+5yCzOhUNdocxB/UQRuYOHRYYwAxKYwJYc0T4D12pDA==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.1.tgz", + "integrity": "sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "dev": true + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "fast-glob": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.1.1.tgz", + "integrity": "sha512-nTCREpBY8w8r+boyFYAx21iL6faSsQynliPHM4Uf56SbkyohCNxpVPEH9xrF5TXKy+IsjkPUHDKiUkzBVRXn9g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.0", + "merge2": "^1.3.0", + "micromatch": "^4.0.2" + } + }, + "fastq": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.6.0.tgz", + "integrity": "sha512-jmxqQ3Z/nXoeyDmWAzF9kH1aGZSis6e/SbfPmJpUnyZ0ogr6iscHQaml4wsEepEWSdtmpy+eVXmCRIMpxaXqOA==", + "dev": true, + "requires": { + "reusify": "^1.0.0" + } + }, + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "find-versions": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-3.2.0.tgz", + "integrity": "sha512-P8WRou2S+oe222TOCHitLy8zj+SIsVJh52VP4lvXkaFVnOFFdoWv1H1Jjvel1aI6NCFOAaeAVm8qrI0odiLcww==", + "dev": true, + "requires": { + "semver-regex": "^2.0.0" + } + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", + "dev": true + }, + "get-stdin": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz", + "integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==", + "dev": true + }, + "get-stream": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", + "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "git-log-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/git-log-parser/-/git-log-parser-1.2.0.tgz", + "integrity": "sha1-LmpMGxP8AAKCB7p5WnrDFme5/Uo=", + "dev": true, + "requires": { + "argv-formatter": "~1.0.0", + "spawn-error-forwarder": "~1.0.0", + "split2": "~1.0.0", + "stream-combiner2": "~1.1.1", + "through2": "~2.0.0", + "traverse": "~0.6.6" + }, + "dependencies": { + "split2": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-1.0.0.tgz", + "integrity": "sha1-UuLiIdiMdfmnP5BVbiY/+WdysxQ=", + "dev": true, + "requires": { + "through2": "~2.0.0" + } + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + } + } + }, + "git-raw-commits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.3.tgz", + "integrity": "sha512-SoSsFL5lnixVzctGEi2uykjA7B5I0AhO9x6kdzvGRHbxsa6JSEgrgy1esRKsfOKE1cgyOJ/KDR2Trxu157sb8w==", + "dev": true, + "requires": { + "dargs": "^4.0.1", + "lodash.template": "^4.0.2", + "meow": "^5.0.0", + "split2": "^2.0.0", + "through2": "^3.0.0" + } + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", + "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "global-dirs": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", + "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", + "dev": true, + "requires": { + "ini": "^1.3.4" + } + }, + "globby": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.0.tgz", + "integrity": "sha512-iuehFnR3xu5wBBtm4xi0dMe92Ob87ufyu/dHwpDYfbcpYpIbrO5OnS8M1vWvrBhSGEJ3/Ecj7gnX76P8YxpPEg==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + } + }, + "graceful-fs": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", + "dev": true + }, + "gradle-semantic-release-plugin": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/gradle-semantic-release-plugin/-/gradle-semantic-release-plugin-1.4.0.tgz", + "integrity": "sha512-NUXMe90hX3juZGpUkb5pUQ4gzqhAhOf/mmETno8wUSDKQRWDT4pSou3OFXEyQXok4Kc/bkOJ8YF0oqtIieUAOg==", + "dev": true, + "requires": { + "promisified-properties": "^2.0.2", + "split2": "^3.1.1" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "split2": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.1.1.tgz", + "integrity": "sha512-emNzr1s7ruq4N+1993yht631/JH+jaj0NYBosuKmLcq+JkGQ9MmTw1RB1fGaTCzUuseRIClrlSLHRNYGwWQ58Q==", + "dev": true, + "requires": { + "readable-stream": "^3.0.0" + } + } + } + }, + "handlebars": { + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.3.tgz", + "integrity": "sha512-SRGwSYuNfx8DwHD/6InAPzD6RgeruWLT+B8e8a7gGs8FWgHzlExpTFMEq2IA6QpAfOClpKHy6+8IqTjeBCu6Kg==", + "dev": true, + "requires": { + "neo-async": "^2.6.0", + "optimist": "^0.6.1", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "hook-std": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hook-std/-/hook-std-2.0.0.tgz", + "integrity": "sha512-zZ6T5WcuBMIUVh49iPQS9t977t7C0l7OtHrpeMb5uk48JdflRX0NSFvCekfYNmGQETnLq9W/isMyHl69kxGi8g==", + "dev": true + }, + "hosted-git-info": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz", + "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==", + "dev": true + }, + "http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + } + }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "dev": true + }, + "husky": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/husky/-/husky-4.2.3.tgz", + "integrity": "sha512-VxTsSTRwYveKXN4SaH1/FefRJYCtx+wx04sSVcOpD7N2zjoHxa+cEJ07Qg5NmV3HAK+IRKOyNVpi2YBIVccIfQ==", + "dev": true, + "requires": { + "chalk": "^3.0.0", + "ci-info": "^2.0.0", + "compare-versions": "^3.5.1", + "cosmiconfig": "^6.0.0", + "find-versions": "^3.2.0", + "opencollective-postinstall": "^2.0.2", + "pkg-dir": "^4.2.0", + "please-upgrade-node": "^3.2.0", + "slash": "^3.0.0", + "which-pm-runs": "^1.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "dev": true, + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "parse-json": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", + "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1", + "lines-and-columns": "^1.1.6" + } + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "ignore": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz", + "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==", + "dev": true + }, + "import-fresh": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } + } + }, + "import-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/import-from/-/import-from-3.0.0.tgz", + "integrity": "sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ==", + "dev": true, + "requires": { + "resolve-from": "^5.0.0" + } + }, + "indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true + }, + "into-stream": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-5.1.1.tgz", + "integrity": "sha512-krrAJ7McQxGGmvaYbB7Q1mcA+cRwg9Ij2RfWIeVesNBgVDZmzY/Fa4IpZUT3bmdRzMzdf/mzltCG2Dq99IZGBA==", + "dev": true, + "requires": { + "from2": "^2.3.0", + "p-is-promise": "^3.0.0" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", + "dev": true + }, + "is-observable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-1.1.0.tgz", + "integrity": "sha512-NqCa4Sa2d+u7BWc6CukaObG3Fh+CU9bvixbpcXYhy2VvYS7vVGIdAgnIS5Ks3A/cqk4rebLJ9s8zBstT2aKnIA==", + "dev": true, + "requires": { + "symbol-observable": "^1.1.0" + } + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true + }, + "is-plain-object": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.0.tgz", + "integrity": "sha512-tZIpofR+P05k8Aocp7UI/2UTa9lTJSebCXpFFoR9aibpokDj/uXBsJ8luUu0tTVYKkMU6URDUuOfJZ7koewXvg==", + "dev": true, + "requires": { + "isobject": "^4.0.0" + } + }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, + "is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-text-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", + "integrity": "sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4=", + "dev": true, + "requires": { + "text-extensions": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-4.0.0.tgz", + "integrity": "sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==", + "dev": true + }, + "issue-parser": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/issue-parser/-/issue-parser-6.0.0.tgz", + "integrity": "sha512-zKa/Dxq2lGsBIXQ7CUZWTHfvxPC2ej0KfO7fIPqLlHB9J2hJ7rGhZ5rilhuufylr4RXYPzJUeFjKxz305OsNlA==", + "dev": true, + "requires": { + "lodash.capitalize": "^4.2.1", + "lodash.escaperegexp": "^4.1.2", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.uniqby": "^4.7.0" + } + }, + "java-properties": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/java-properties/-/java-properties-1.0.2.tgz", + "integrity": "sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", + "dev": true + }, + "lines-and-columns": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", + "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", + "dev": true + }, + "lint-staged": { + "version": "10.0.7", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-10.0.7.tgz", + "integrity": "sha512-Byj0F4l7GYUpYYHEqyFH69NiI6ICTg0CeCKbhRorL+ickbzILKUlZLiyCkljZV02wnoh7yH7PmFyYm9PRNwk9g==", + "dev": true, + "requires": { + "chalk": "^3.0.0", + "commander": "^4.0.1", + "cosmiconfig": "^6.0.0", + "debug": "^4.1.1", + "dedent": "^0.7.0", + "execa": "^3.4.0", + "listr": "^0.14.3", + "log-symbols": "^3.0.0", + "micromatch": "^4.0.2", + "normalize-path": "^3.0.0", + "please-upgrade-node": "^3.2.0", + "string-argv": "0.3.1", + "stringify-object": "^3.3.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "dev": true, + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + } + }, + "cross-spawn": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.1.tgz", + "integrity": "sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "execa": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-3.4.0.tgz", + "integrity": "sha512-r9vdGQk4bmCuK1yKQu1KTwcT2zwfWdbdaXfCtAh+5nU/4fSX+JAb7vZGvI5naJrQlvONrEB20jeruESI69530g==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "p-finally": "^2.0.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + } + }, + "get-stream": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", + "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "dev": true + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "p-finally": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-2.0.1.tgz", + "integrity": "sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw==", + "dev": true + }, + "parse-json": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", + "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1", + "lines-and-columns": "^1.1.6" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "listr": { + "version": "0.14.3", + "resolved": "https://registry.npmjs.org/listr/-/listr-0.14.3.tgz", + "integrity": "sha512-RmAl7su35BFd/xoMamRjpIE4j3v+L28o8CT5YhAXQJm1fD+1l9ngXY8JAQRJ+tFK2i5njvi0iRUKV09vPwA0iA==", + "dev": true, + "requires": { + "@samverschueren/stream-to-observable": "^0.3.0", + "is-observable": "^1.1.0", + "is-promise": "^2.1.0", + "is-stream": "^1.1.0", + "listr-silent-renderer": "^1.1.1", + "listr-update-renderer": "^0.5.0", + "listr-verbose-renderer": "^0.5.0", + "p-map": "^2.0.0", + "rxjs": "^6.3.3" + } + }, + "listr-silent-renderer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz", + "integrity": "sha1-kktaN1cVN3C/Go4/v3S4u/P5JC4=", + "dev": true + }, + "listr-update-renderer": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/listr-update-renderer/-/listr-update-renderer-0.5.0.tgz", + "integrity": "sha512-tKRsZpKz8GSGqoI/+caPmfrypiaq+OQCbd+CovEC24uk1h952lVj5sC7SqyFUm+OaJ5HN/a1YLt5cit2FMNsFA==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "cli-truncate": "^0.2.1", + "elegant-spinner": "^1.0.1", + "figures": "^1.7.0", + "indent-string": "^3.0.0", + "log-symbols": "^1.0.2", + "log-update": "^2.3.0", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "log-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", + "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", + "dev": true, + "requires": { + "chalk": "^1.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "listr-verbose-renderer": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.5.0.tgz", + "integrity": "sha512-04PDPqSlsqIOaaaGZ+41vq5FejI9auqTInicFRndCBgE3bXG8D6W1I+mWhk+1nqbHmyhla/6BUrd5OSiHwKRXw==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "cli-cursor": "^2.1.0", + "date-fns": "^1.27.2", + "figures": "^2.0.0" + }, + "dependencies": { + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + } + } + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "lodash._reinterpolate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", + "dev": true + }, + "lodash.capitalize": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz", + "integrity": "sha1-+CbJtOKoUR2E46yinbBeGk87cqk=", + "dev": true + }, + "lodash.escaperegexp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", + "integrity": "sha1-ZHYsSGGAglGKw99Mz11YhtriA0c=", + "dev": true + }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", + "dev": true + }, + "lodash.ismatch": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", + "integrity": "sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc=", + "dev": true + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=", + "dev": true + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=", + "dev": true + }, + "lodash.set": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", + "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=", + "dev": true + }, + "lodash.template": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", + "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", + "dev": true, + "requires": { + "lodash._reinterpolate": "^3.0.0", + "lodash.templatesettings": "^4.0.0" + } + }, + "lodash.templatesettings": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", + "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", + "dev": true, + "requires": { + "lodash._reinterpolate": "^3.0.0" + } + }, + "lodash.toarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", + "integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE=", + "dev": true + }, + "lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", + "dev": true + }, + "lodash.uniqby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz", + "integrity": "sha1-2ZwHpmnp5tJOE2Lf4mbGdhavEwI=", + "dev": true + }, + "log-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2" + } + }, + "log-update": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-2.3.0.tgz", + "integrity": "sha1-iDKP19HOeTiykoN0bwsbwSayRwg=", + "dev": true, + "requires": { + "ansi-escapes": "^3.0.0", + "cli-cursor": "^2.0.0", + "wrap-ansi": "^3.0.1" + } + }, + "loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "dev": true, + "requires": { + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" + } + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "macos-release": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-2.3.0.tgz", + "integrity": "sha512-OHhSbtcviqMPt7yfw5ef5aghS2jzFVKEFyCJndQt2YpSQ9qRVSEv2axSJI1paVThEu+FFGs584h/1YhxjVqajA==", + "dev": true + }, + "map-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-2.0.0.tgz", + "integrity": "sha1-plzSkIepJZi4eRJXpSPgISIqwfk=", + "dev": true + }, + "marked": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.8.0.tgz", + "integrity": "sha512-MyUe+T/Pw4TZufHkzAfDj6HarCBWia2y27/bhuYkTaiUnfDYFnCP3KUN+9oM7Wi6JA2rymtVYbQu3spE0GCmxQ==", + "dev": true + }, + "marked-terminal": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-4.0.0.tgz", + "integrity": "sha512-mzU3VD7aVz12FfGoKFAceijehA6Ocjfg3rVimvJbFAB/NOYCsuzRVtq3PSFdPmWI5mhdGeEh3/aMJ5DSxAz94Q==", + "dev": true, + "requires": { + "ansi-escapes": "^4.3.0", + "cardinal": "^2.1.1", + "chalk": "^3.0.0", + "cli-table": "^0.3.1", + "node-emoji": "^1.10.0", + "supports-hyperlinks": "^2.0.0" + }, + "dependencies": { + "ansi-escapes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.0.tgz", + "integrity": "sha512-EiYhwo0v255HUL6eDyuLrXEkTi7WwVCLAw+SeOQ7M7qdun1z1pum4DEm/nuqIVbPvi9RPPc9k9LbyBv6H0DwVg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + } + } + }, + "meow": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-5.0.0.tgz", + "integrity": "sha512-CbTqYU17ABaLefO8vCU153ZZlprKYWDljcndKKDCFcYQITzWCXZAVk4QMFZPgvzrnUQ3uItnIE/LoUOwrT15Ig==", + "dev": true, + "requires": { + "camelcase-keys": "^4.0.0", + "decamelize-keys": "^1.0.0", + "loud-rejection": "^1.0.0", + "minimist-options": "^3.0.1", + "normalize-package-data": "^2.3.4", + "read-pkg-up": "^3.0.0", + "redent": "^2.0.0", + "trim-newlines": "^2.0.0", + "yargs-parser": "^10.0.0" + } + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "merge2": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.3.0.tgz", + "integrity": "sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw==", + "dev": true + }, + "micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "dev": true, + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.0.5" + } + }, + "mime": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", + "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", + "dev": true + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "minimist-options": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-3.0.2.tgz", + "integrity": "sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0" + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "modify-values": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", + "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "neo-async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", + "dev": true + }, + "nerf-dart": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/nerf-dart/-/nerf-dart-1.0.0.tgz", + "integrity": "sha1-5tq3/r9a2Bbqgc9cYpxaDr3nLBo=", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node-emoji": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.10.0.tgz", + "integrity": "sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw==", + "dev": true, + "requires": { + "lodash.toarray": "^4.4.0" + } + }, + "node-fetch": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", + "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==", + "dev": true + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "normalize-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-5.0.0.tgz", + "integrity": "sha512-bAEm2fx8Dq/a35Z6PIRkkBBJvR56BbEJvhpNtvCZ4W9FyORSna77fn+xtYFjqk5JpBS+fMnAOG/wFgkQBmB7hw==", + "dev": true + }, + "npm": { + "version": "6.13.7", + "resolved": "https://registry.npmjs.org/npm/-/npm-6.13.7.tgz", + "integrity": "sha512-X967EKTT407CvgrWFjXusnPh0VLERcmR9hZFSVgkEquOomZkvpwLJ5zrQ3qrG9SpPLKJE4bPLUu76exKQ4a3Cg==", + "dev": true, + "requires": { + "JSONStream": "^1.3.5", + "abbrev": "~1.1.1", + "ansicolors": "~0.3.2", + "ansistyles": "~0.1.3", + "aproba": "^2.0.0", + "archy": "~1.0.0", + "bin-links": "^1.1.7", + "bluebird": "^3.5.5", + "byte-size": "^5.0.1", + "cacache": "^12.0.3", + "call-limit": "^1.1.1", + "chownr": "^1.1.3", + "ci-info": "^2.0.0", + "cli-columns": "^3.1.2", + "cli-table3": "^0.5.1", + "cmd-shim": "^3.0.3", + "columnify": "~1.5.4", + "config-chain": "^1.1.12", + "debuglog": "*", + "detect-indent": "~5.0.0", + "detect-newline": "^2.1.0", + "dezalgo": "~1.0.3", + "editor": "~1.0.0", + "figgy-pudding": "^3.5.1", + "find-npm-prefix": "^1.0.2", + "fs-vacuum": "~1.2.10", + "fs-write-stream-atomic": "~1.0.10", + "gentle-fs": "^2.3.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.3", + "has-unicode": "~2.0.1", + "hosted-git-info": "^2.8.5", + "iferr": "^1.0.2", + "imurmurhash": "*", + "infer-owner": "^1.0.4", + "inflight": "~1.0.6", + "inherits": "^2.0.4", + "ini": "^1.3.5", + "init-package-json": "^1.10.3", + "is-cidr": "^3.0.0", + "json-parse-better-errors": "^1.0.2", + "lazy-property": "~1.0.0", + "libcipm": "^4.0.7", + "libnpm": "^3.0.1", + "libnpmaccess": "^3.0.2", + "libnpmhook": "^5.0.3", + "libnpmorg": "^1.0.1", + "libnpmsearch": "^2.0.2", + "libnpmteam": "^1.0.2", + "libnpx": "^10.2.2", + "lock-verify": "^2.1.0", + "lockfile": "^1.0.4", + "lodash._baseindexof": "*", + "lodash._baseuniq": "~4.6.0", + "lodash._bindcallback": "*", + "lodash._cacheindexof": "*", + "lodash._createcache": "*", + "lodash._getnative": "*", + "lodash.clonedeep": "~4.5.0", + "lodash.restparam": "*", + "lodash.union": "~4.6.0", + "lodash.uniq": "~4.5.0", + "lodash.without": "~4.4.0", + "lru-cache": "^5.1.1", + "meant": "~1.0.1", + "mississippi": "^3.0.0", + "mkdirp": "~0.5.1", + "move-concurrently": "^1.0.1", + "node-gyp": "^5.0.7", + "nopt": "~4.0.1", + "normalize-package-data": "^2.5.0", + "npm-audit-report": "^1.3.2", + "npm-cache-filename": "~1.0.2", + "npm-install-checks": "^3.0.2", + "npm-lifecycle": "^3.1.4", + "npm-package-arg": "^6.1.1", + "npm-packlist": "^1.4.7", + "npm-pick-manifest": "^3.0.2", + "npm-profile": "^4.0.2", + "npm-registry-fetch": "^4.0.2", + "npm-user-validate": "~1.0.0", + "npmlog": "~4.1.2", + "once": "~1.4.0", + "opener": "^1.5.1", + "osenv": "^0.1.5", + "pacote": "^9.5.12", + "path-is-inside": "~1.0.2", + "promise-inflight": "~1.0.1", + "qrcode-terminal": "^0.12.0", + "query-string": "^6.8.2", + "qw": "~1.0.1", + "read": "~1.0.7", + "read-cmd-shim": "^1.0.5", + "read-installed": "~4.0.3", + "read-package-json": "^2.1.1", + "read-package-tree": "^5.3.1", + "readable-stream": "^3.4.0", + "readdir-scoped-modules": "^1.1.0", + "request": "^2.88.0", + "retry": "^0.12.0", + "rimraf": "^2.6.3", + "safe-buffer": "^5.1.2", + "semver": "^5.7.1", + "sha": "^3.0.0", + "slide": "~1.1.6", + "sorted-object": "~2.0.1", + "sorted-union-stream": "~2.1.3", + "ssri": "^6.0.1", + "stringify-package": "^1.0.1", + "tar": "^4.4.13", + "text-table": "~0.2.0", + "tiny-relative-date": "^1.3.0", + "uid-number": "0.0.6", + "umask": "~1.1.0", + "unique-filename": "^1.1.1", + "unpipe": "~1.0.0", + "update-notifier": "^2.5.0", + "uuid": "^3.3.3", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "~3.0.0", + "which": "^1.3.1", + "worker-farm": "^1.7.0", + "write-file-atomic": "^2.4.3" + }, + "dependencies": { + "JSONStream": { + "version": "1.3.5", + "bundled": true, + "dev": true, + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + } + }, + "abbrev": { + "version": "1.1.1", + "bundled": true, + "dev": true + }, + "agent-base": { + "version": "4.3.0", + "bundled": true, + "dev": true, + "requires": { + "es6-promisify": "^5.0.0" + } + }, + "agentkeepalive": { + "version": "3.5.2", + "bundled": true, + "dev": true, + "requires": { + "humanize-ms": "^1.2.1" + } + }, + "ajv": { + "version": "5.5.2", + "bundled": true, + "dev": true, + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "ansi-align": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "string-width": "^2.0.0" + } + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "bundled": true, + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "ansicolors": { + "version": "0.3.2", + "bundled": true, + "dev": true + }, + "ansistyles": { + "version": "0.1.3", + "bundled": true, + "dev": true + }, + "aproba": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "archy": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "are-we-there-yet": { + "version": "1.1.4", + "bundled": true, + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "asap": { + "version": "2.0.6", + "bundled": true, + "dev": true + }, + "asn1": { + "version": "0.2.4", + "bundled": true, + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "bundled": true, + "dev": true + }, + "aws-sign2": { + "version": "0.7.0", + "bundled": true, + "dev": true + }, + "aws4": { + "version": "1.8.0", + "bundled": true, + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "bin-links": { + "version": "1.1.7", + "bundled": true, + "dev": true, + "requires": { + "bluebird": "^3.5.3", + "cmd-shim": "^3.0.0", + "gentle-fs": "^2.3.0", + "graceful-fs": "^4.1.15", + "npm-normalize-package-bin": "^1.0.0", + "write-file-atomic": "^2.3.0" + } + }, + "bluebird": { + "version": "3.5.5", + "bundled": true, + "dev": true + }, + "boxen": { + "version": "1.3.0", + "bundled": true, + "dev": true, + "requires": { + "ansi-align": "^2.0.0", + "camelcase": "^4.0.0", + "chalk": "^2.0.1", + "cli-boxes": "^1.0.0", + "string-width": "^2.0.0", + "term-size": "^1.2.0", + "widest-line": "^2.0.0" + } + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "buffer-from": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "builtins": { + "version": "1.0.3", + "bundled": true, + "dev": true + }, + "byline": { + "version": "5.0.0", + "bundled": true, + "dev": true + }, + "byte-size": { + "version": "5.0.1", + "bundled": true, + "dev": true + }, + "cacache": { + "version": "12.0.3", + "bundled": true, + "dev": true, + "requires": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + } + }, + "call-limit": { + "version": "1.1.1", + "bundled": true, + "dev": true + }, + "camelcase": { + "version": "4.1.0", + "bundled": true, + "dev": true + }, + "capture-stack-trace": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "caseless": { + "version": "0.12.0", + "bundled": true, + "dev": true + }, + "chalk": { + "version": "2.4.1", + "bundled": true, + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chownr": { + "version": "1.1.3", + "bundled": true, + "dev": true + }, + "ci-info": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "cidr-regex": { + "version": "2.0.10", + "bundled": true, + "dev": true, + "requires": { + "ip-regex": "^2.1.0" + } + }, + "cli-boxes": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "cli-columns": { + "version": "3.1.2", + "bundled": true, + "dev": true, + "requires": { + "string-width": "^2.0.0", + "strip-ansi": "^3.0.1" + } + }, + "cli-table3": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "requires": { + "colors": "^1.1.2", + "object-assign": "^4.1.0", + "string-width": "^2.1.1" + } + }, + "cliui": { + "version": "4.1.0", + "bundled": true, + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "clone": { + "version": "1.0.4", + "bundled": true, + "dev": true + }, + "cmd-shim": { + "version": "3.0.3", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "mkdirp": "~0.5.0" + } + }, + "co": { + "version": "4.6.0", + "bundled": true, + "dev": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "color-convert": { + "version": "1.9.1", + "bundled": true, + "dev": true, + "requires": { + "color-name": "^1.1.1" + } + }, + "color-name": { + "version": "1.1.3", + "bundled": true, + "dev": true + }, + "colors": { + "version": "1.3.3", + "bundled": true, + "dev": true, + "optional": true + }, + "columnify": { + "version": "1.5.4", + "bundled": true, + "dev": true, + "requires": { + "strip-ansi": "^3.0.0", + "wcwidth": "^1.0.0" + } + }, + "combined-stream": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true + }, + "concat-stream": { + "version": "1.6.2", + "bundled": true, + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "config-chain": { + "version": "1.1.12", + "bundled": true, + "dev": true, + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "configstore": { + "version": "3.1.2", + "bundled": true, + "dev": true, + "requires": { + "dot-prop": "^4.1.0", + "graceful-fs": "^4.1.2", + "make-dir": "^1.0.0", + "unique-string": "^1.0.0", + "write-file-atomic": "^2.0.0", + "xdg-basedir": "^3.0.0" + } + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "copy-concurrently": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + }, + "dependencies": { + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true + }, + "iferr": { + "version": "0.1.5", + "bundled": true, + "dev": true + } + } + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "create-error-class": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "requires": { + "capture-stack-trace": "^1.0.0" + } + }, + "cross-spawn": { + "version": "5.1.0", + "bundled": true, + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "lru-cache": { + "version": "4.1.5", + "bundled": true, + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "yallist": { + "version": "2.1.2", + "bundled": true, + "dev": true + } + } + }, + "crypto-random-string": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "cyclist": { + "version": "0.2.2", + "bundled": true, + "dev": true + }, + "dashdash": { + "version": "1.14.1", + "bundled": true, + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "debug": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "bundled": true, + "dev": true + } + } + }, + "debuglog": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "decamelize": { + "version": "1.2.0", + "bundled": true, + "dev": true + }, + "decode-uri-component": { + "version": "0.2.0", + "bundled": true, + "dev": true + }, + "deep-extend": { + "version": "0.5.1", + "bundled": true, + "dev": true + }, + "defaults": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "requires": { + "clone": "^1.0.2" + } + }, + "define-properties": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "delayed-stream": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "detect-indent": { + "version": "5.0.0", + "bundled": true, + "dev": true + }, + "detect-newline": { + "version": "2.1.0", + "bundled": true, + "dev": true + }, + "dezalgo": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "requires": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "dot-prop": { + "version": "4.2.0", + "bundled": true, + "dev": true, + "requires": { + "is-obj": "^1.0.0" + } + }, + "dotenv": { + "version": "5.0.1", + "bundled": true, + "dev": true + }, + "duplexer3": { + "version": "0.1.4", + "bundled": true, + "dev": true + }, + "duplexify": { + "version": "3.6.0", + "bundled": true, + "dev": true, + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "editor": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "encoding": { + "version": "0.1.12", + "bundled": true, + "dev": true, + "requires": { + "iconv-lite": "~0.4.13" + } + }, + "end-of-stream": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "env-paths": { + "version": "2.2.0", + "bundled": true, + "dev": true + }, + "err-code": { + "version": "1.1.2", + "bundled": true, + "dev": true + }, + "errno": { + "version": "0.1.7", + "bundled": true, + "dev": true, + "requires": { + "prr": "~1.0.1" + } + }, + "es-abstract": { + "version": "1.12.0", + "bundled": true, + "dev": true, + "requires": { + "es-to-primitive": "^1.1.1", + "function-bind": "^1.1.1", + "has": "^1.0.1", + "is-callable": "^1.1.3", + "is-regex": "^1.0.4" + } + }, + "es-to-primitive": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es6-promise": { + "version": "4.2.8", + "bundled": true, + "dev": true + }, + "es6-promisify": { + "version": "5.0.0", + "bundled": true, + "dev": true, + "requires": { + "es6-promise": "^4.0.3" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "bundled": true, + "dev": true + }, + "execa": { + "version": "0.7.0", + "bundled": true, + "dev": true, + "requires": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "dependencies": { + "get-stream": { + "version": "3.0.0", + "bundled": true, + "dev": true + } + } + }, + "extend": { + "version": "3.0.2", + "bundled": true, + "dev": true + }, + "extsprintf": { + "version": "1.3.0", + "bundled": true, + "dev": true + }, + "fast-deep-equal": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "figgy-pudding": { + "version": "3.5.1", + "bundled": true, + "dev": true + }, + "find-npm-prefix": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "find-up": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "flush-write-stream": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.4" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "forever-agent": { + "version": "0.6.1", + "bundled": true, + "dev": true + }, + "form-data": { + "version": "2.3.2", + "bundled": true, + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "1.0.6", + "mime-types": "^2.1.12" + } + }, + "from2": { + "version": "2.3.0", + "bundled": true, + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "fs-minipass": { + "version": "1.2.7", + "bundled": true, + "dev": true, + "requires": { + "minipass": "^2.6.0" + }, + "dependencies": { + "minipass": { + "version": "2.9.0", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + } + } + }, + "fs-vacuum": { + "version": "1.2.10", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "path-is-inside": "^1.0.1", + "rimraf": "^2.5.2" + } + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + }, + "dependencies": { + "iferr": { + "version": "0.1.5", + "bundled": true, + "dev": true + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "function-bind": { + "version": "1.1.1", + "bundled": true, + "dev": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + }, + "dependencies": { + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, + "genfun": { + "version": "5.0.0", + "bundled": true, + "dev": true + }, + "gentle-fs": { + "version": "2.3.0", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^1.1.2", + "chownr": "^1.1.2", + "cmd-shim": "^3.0.3", + "fs-vacuum": "^1.2.10", + "graceful-fs": "^4.1.11", + "iferr": "^0.1.5", + "infer-owner": "^1.0.4", + "mkdirp": "^0.5.1", + "path-is-inside": "^1.0.2", + "read-cmd-shim": "^1.0.1", + "slide": "^1.1.6" + }, + "dependencies": { + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true + }, + "iferr": { + "version": "0.1.5", + "bundled": true, + "dev": true + } + } + }, + "get-caller-file": { + "version": "1.0.3", + "bundled": true, + "dev": true + }, + "get-stream": { + "version": "4.1.0", + "bundled": true, + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "getpass": { + "version": "0.1.7", + "bundled": true, + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.1.4", + "bundled": true, + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "global-dirs": { + "version": "0.1.1", + "bundled": true, + "dev": true, + "requires": { + "ini": "^1.3.4" + } + }, + "got": { + "version": "6.7.1", + "bundled": true, + "dev": true, + "requires": { + "create-error-class": "^3.0.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "is-redirect": "^1.0.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "lowercase-keys": "^1.0.0", + "safe-buffer": "^5.0.1", + "timed-out": "^4.0.0", + "unzip-response": "^2.0.1", + "url-parse-lax": "^1.0.0" + }, + "dependencies": { + "get-stream": { + "version": "3.0.0", + "bundled": true, + "dev": true + } + } + }, + "graceful-fs": { + "version": "4.2.3", + "bundled": true, + "dev": true + }, + "har-schema": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "har-validator": { + "version": "5.1.0", + "bundled": true, + "dev": true, + "requires": { + "ajv": "^5.3.0", + "har-schema": "^2.0.0" + } + }, + "has": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "has-symbols": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true + }, + "hosted-git-info": { + "version": "2.8.5", + "bundled": true, + "dev": true + }, + "http-cache-semantics": { + "version": "3.8.1", + "bundled": true, + "dev": true + }, + "http-proxy-agent": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "agent-base": "4", + "debug": "3.1.0" + } + }, + "http-signature": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "https-proxy-agent": { + "version": "2.2.4", + "bundled": true, + "dev": true, + "requires": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + } + }, + "humanize-ms": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "requires": { + "ms": "^2.0.0" + } + }, + "iconv-lite": { + "version": "0.4.23", + "bundled": true, + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "iferr": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "ignore-walk": { + "version": "3.0.3", + "bundled": true, + "dev": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "import-lazy": { + "version": "2.1.0", + "bundled": true, + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "bundled": true, + "dev": true + }, + "infer-owner": { + "version": "1.0.4", + "bundled": true, + "dev": true + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "bundled": true, + "dev": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "dev": true + }, + "init-package-json": { + "version": "1.10.3", + "bundled": true, + "dev": true, + "requires": { + "glob": "^7.1.1", + "npm-package-arg": "^4.0.0 || ^5.0.0 || ^6.0.0", + "promzard": "^0.3.0", + "read": "~1.0.1", + "read-package-json": "1 || 2", + "semver": "2.x || 3.x || 4 || 5", + "validate-npm-package-license": "^3.0.1", + "validate-npm-package-name": "^3.0.0" + } + }, + "invert-kv": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "ip": { + "version": "1.1.5", + "bundled": true, + "dev": true + }, + "ip-regex": { + "version": "2.1.0", + "bundled": true, + "dev": true + }, + "is-callable": { + "version": "1.1.4", + "bundled": true, + "dev": true + }, + "is-ci": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "ci-info": "^1.0.0" + }, + "dependencies": { + "ci-info": { + "version": "1.6.0", + "bundled": true, + "dev": true + } + } + }, + "is-cidr": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "cidr-regex": "^2.0.10" + } + }, + "is-date-object": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-installed-globally": { + "version": "0.1.0", + "bundled": true, + "dev": true, + "requires": { + "global-dirs": "^0.1.0", + "is-path-inside": "^1.0.0" + } + }, + "is-npm": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "is-obj": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "is-path-inside": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "path-is-inside": "^1.0.1" + } + }, + "is-redirect": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "is-regex": { + "version": "1.0.4", + "bundled": true, + "dev": true, + "requires": { + "has": "^1.0.1" + } + }, + "is-retry-allowed": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "is-symbol": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "has-symbols": "^1.0.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "isexe": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "isstream": { + "version": "0.1.2", + "bundled": true, + "dev": true + }, + "jsbn": { + "version": "0.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "bundled": true, + "dev": true + }, + "json-schema-traverse": { + "version": "0.3.1", + "bundled": true, + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "bundled": true, + "dev": true + }, + "jsonparse": { + "version": "1.3.1", + "bundled": true, + "dev": true + }, + "jsprim": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "latest-version": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "package-json": "^4.0.0" + } + }, + "lazy-property": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "lcid": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, + "libcipm": { + "version": "4.0.7", + "bundled": true, + "dev": true, + "requires": { + "bin-links": "^1.1.2", + "bluebird": "^3.5.1", + "figgy-pudding": "^3.5.1", + "find-npm-prefix": "^1.0.2", + "graceful-fs": "^4.1.11", + "ini": "^1.3.5", + "lock-verify": "^2.0.2", + "mkdirp": "^0.5.1", + "npm-lifecycle": "^3.0.0", + "npm-logical-tree": "^1.2.1", + "npm-package-arg": "^6.1.0", + "pacote": "^9.1.0", + "read-package-json": "^2.0.13", + "rimraf": "^2.6.2", + "worker-farm": "^1.6.0" + } + }, + "libnpm": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "bin-links": "^1.1.2", + "bluebird": "^3.5.3", + "find-npm-prefix": "^1.0.2", + "libnpmaccess": "^3.0.2", + "libnpmconfig": "^1.2.1", + "libnpmhook": "^5.0.3", + "libnpmorg": "^1.0.1", + "libnpmpublish": "^1.1.2", + "libnpmsearch": "^2.0.2", + "libnpmteam": "^1.0.2", + "lock-verify": "^2.0.2", + "npm-lifecycle": "^3.0.0", + "npm-logical-tree": "^1.2.1", + "npm-package-arg": "^6.1.0", + "npm-profile": "^4.0.2", + "npm-registry-fetch": "^4.0.0", + "npmlog": "^4.1.2", + "pacote": "^9.5.3", + "read-package-json": "^2.0.13", + "stringify-package": "^1.0.0" + } + }, + "libnpmaccess": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^2.0.0", + "get-stream": "^4.0.0", + "npm-package-arg": "^6.1.0", + "npm-registry-fetch": "^4.0.0" + } + }, + "libnpmconfig": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1", + "find-up": "^3.0.0", + "ini": "^1.3.5" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.2.0", + "bundled": true, + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "bundled": true, + "dev": true + } + } + }, + "libnpmhook": { + "version": "5.0.3", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^2.0.0", + "figgy-pudding": "^3.4.1", + "get-stream": "^4.0.0", + "npm-registry-fetch": "^4.0.0" + } + }, + "libnpmorg": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^2.0.0", + "figgy-pudding": "^3.4.1", + "get-stream": "^4.0.0", + "npm-registry-fetch": "^4.0.0" + } + }, + "libnpmpublish": { + "version": "1.1.2", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^2.0.0", + "figgy-pudding": "^3.5.1", + "get-stream": "^4.0.0", + "lodash.clonedeep": "^4.5.0", + "normalize-package-data": "^2.4.0", + "npm-package-arg": "^6.1.0", + "npm-registry-fetch": "^4.0.0", + "semver": "^5.5.1", + "ssri": "^6.0.1" + } + }, + "libnpmsearch": { + "version": "2.0.2", + "bundled": true, + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1", + "get-stream": "^4.0.0", + "npm-registry-fetch": "^4.0.0" + } + }, + "libnpmteam": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^2.0.0", + "figgy-pudding": "^3.4.1", + "get-stream": "^4.0.0", + "npm-registry-fetch": "^4.0.0" + } + }, + "libnpx": { + "version": "10.2.2", + "bundled": true, + "dev": true, + "requires": { + "dotenv": "^5.0.1", + "npm-package-arg": "^6.0.0", + "rimraf": "^2.6.2", + "safe-buffer": "^5.1.0", + "update-notifier": "^2.3.0", + "which": "^1.3.0", + "y18n": "^4.0.0", + "yargs": "^11.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "lock-verify": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "npm-package-arg": "^6.1.0", + "semver": "^5.4.1" + } + }, + "lockfile": { + "version": "1.0.4", + "bundled": true, + "dev": true, + "requires": { + "signal-exit": "^3.0.2" + } + }, + "lodash._baseindexof": { + "version": "3.1.0", + "bundled": true, + "dev": true + }, + "lodash._baseuniq": { + "version": "4.6.0", + "bundled": true, + "dev": true, + "requires": { + "lodash._createset": "~4.0.0", + "lodash._root": "~3.0.0" + } + }, + "lodash._bindcallback": { + "version": "3.0.1", + "bundled": true, + "dev": true + }, + "lodash._cacheindexof": { + "version": "3.0.2", + "bundled": true, + "dev": true + }, + "lodash._createcache": { + "version": "3.1.2", + "bundled": true, + "dev": true, + "requires": { + "lodash._getnative": "^3.0.0" + } + }, + "lodash._createset": { + "version": "4.0.3", + "bundled": true, + "dev": true + }, + "lodash._getnative": { + "version": "3.9.1", + "bundled": true, + "dev": true + }, + "lodash._root": { + "version": "3.0.1", + "bundled": true, + "dev": true + }, + "lodash.clonedeep": { + "version": "4.5.0", + "bundled": true, + "dev": true + }, + "lodash.restparam": { + "version": "3.6.1", + "bundled": true, + "dev": true + }, + "lodash.union": { + "version": "4.6.0", + "bundled": true, + "dev": true + }, + "lodash.uniq": { + "version": "4.5.0", + "bundled": true, + "dev": true + }, + "lodash.without": { + "version": "4.4.0", + "bundled": true, + "dev": true + }, + "lowercase-keys": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "lru-cache": { + "version": "5.1.1", + "bundled": true, + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "make-dir": { + "version": "1.3.0", + "bundled": true, + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "make-fetch-happen": { + "version": "5.0.2", + "bundled": true, + "dev": true, + "requires": { + "agentkeepalive": "^3.4.1", + "cacache": "^12.0.0", + "http-cache-semantics": "^3.8.1", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "node-fetch-npm": "^2.0.2", + "promise-retry": "^1.1.1", + "socks-proxy-agent": "^4.0.0", + "ssri": "^6.0.0" + } + }, + "map-age-cleaner": { + "version": "0.1.3", + "bundled": true, + "dev": true, + "requires": { + "p-defer": "^1.0.0" + } + }, + "meant": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "mem": { + "version": "4.3.0", + "bundled": true, + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + }, + "dependencies": { + "mimic-fn": { + "version": "2.1.0", + "bundled": true, + "dev": true + } + } + }, + "mime-db": { + "version": "1.35.0", + "bundled": true, + "dev": true + }, + "mime-types": { + "version": "2.1.19", + "bundled": true, + "dev": true, + "requires": { + "mime-db": "~1.35.0" + } + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true + }, + "minizlib": { + "version": "1.3.3", + "bundled": true, + "dev": true, + "requires": { + "minipass": "^2.9.0" + }, + "dependencies": { + "minipass": { + "version": "2.9.0", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + } + } + }, + "mississippi": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^3.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "move-concurrently": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + }, + "dependencies": { + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true + } + } + }, + "ms": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "mute-stream": { + "version": "0.0.7", + "bundled": true, + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "bundled": true, + "dev": true + }, + "node-fetch-npm": { + "version": "2.0.2", + "bundled": true, + "dev": true, + "requires": { + "encoding": "^0.1.11", + "json-parse-better-errors": "^1.0.0", + "safe-buffer": "^5.1.1" + } + }, + "node-gyp": { + "version": "5.0.7", + "bundled": true, + "dev": true, + "requires": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.2", + "mkdirp": "^0.5.1", + "nopt": "^4.0.1", + "npmlog": "^4.1.2", + "request": "^2.88.0", + "rimraf": "^2.6.3", + "semver": "^5.7.1", + "tar": "^4.4.12", + "which": "^1.3.1" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "normalize-package-data": { + "version": "2.5.0", + "bundled": true, + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "resolve": { + "version": "1.10.0", + "bundled": true, + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + } + } + }, + "npm-audit-report": { + "version": "1.3.2", + "bundled": true, + "dev": true, + "requires": { + "cli-table3": "^0.5.0", + "console-control-strings": "^1.1.0" + } + }, + "npm-bundled": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-cache-filename": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "npm-install-checks": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "requires": { + "semver": "^2.3.0 || 3.x || 4 || 5" + } + }, + "npm-lifecycle": { + "version": "3.1.4", + "bundled": true, + "dev": true, + "requires": { + "byline": "^5.0.0", + "graceful-fs": "^4.1.15", + "node-gyp": "^5.0.2", + "resolve-from": "^4.0.0", + "slide": "^1.1.6", + "uid-number": "0.0.6", + "umask": "^1.1.0", + "which": "^1.3.1" + } + }, + "npm-logical-tree": { + "version": "1.2.1", + "bundled": true, + "dev": true + }, + "npm-normalize-package-bin": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "npm-package-arg": { + "version": "6.1.1", + "bundled": true, + "dev": true, + "requires": { + "hosted-git-info": "^2.7.1", + "osenv": "^0.1.5", + "semver": "^5.6.0", + "validate-npm-package-name": "^3.0.0" + } + }, + "npm-packlist": { + "version": "1.4.7", + "bundled": true, + "dev": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npm-pick-manifest": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1", + "npm-package-arg": "^6.0.0", + "semver": "^5.4.1" + } + }, + "npm-profile": { + "version": "4.0.2", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^1.1.2 || 2", + "figgy-pudding": "^3.4.1", + "npm-registry-fetch": "^4.0.0" + } + }, + "npm-registry-fetch": { + "version": "4.0.2", + "bundled": true, + "dev": true, + "requires": { + "JSONStream": "^1.3.4", + "bluebird": "^3.5.1", + "figgy-pudding": "^3.4.1", + "lru-cache": "^5.1.1", + "make-fetch-happen": "^5.0.0", + "npm-package-arg": "^6.1.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.0", + "bundled": true, + "dev": true + } + } + }, + "npm-run-path": { + "version": "2.0.2", + "bundled": true, + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "npm-user-validate": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "dev": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "oauth-sign": { + "version": "0.9.0", + "bundled": true, + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true + }, + "object-keys": { + "version": "1.0.12", + "bundled": true, + "dev": true + }, + "object.getownpropertydescriptors": { + "version": "2.0.3", + "bundled": true, + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.5.1" + } + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "opener": { + "version": "1.5.1", + "bundled": true, + "dev": true + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "os-locale": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.5", + "bundled": true, + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + } + } + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "dev": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "p-defer": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "p-finally": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "p-is-promise": { + "version": "2.1.0", + "bundled": true, + "dev": true + }, + "p-limit": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "package-json": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "requires": { + "got": "^6.7.1", + "registry-auth-token": "^3.0.1", + "registry-url": "^3.0.3", + "semver": "^5.1.0" + } + }, + "pacote": { + "version": "9.5.12", + "bundled": true, + "dev": true, + "requires": { + "bluebird": "^3.5.3", + "cacache": "^12.0.2", + "chownr": "^1.1.2", + "figgy-pudding": "^3.5.1", + "get-stream": "^4.1.0", + "glob": "^7.1.3", + "infer-owner": "^1.0.4", + "lru-cache": "^5.1.1", + "make-fetch-happen": "^5.0.0", + "minimatch": "^3.0.4", + "minipass": "^2.3.5", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "normalize-package-data": "^2.4.0", + "npm-normalize-package-bin": "^1.0.0", + "npm-package-arg": "^6.1.0", + "npm-packlist": "^1.1.12", + "npm-pick-manifest": "^3.0.0", + "npm-registry-fetch": "^4.0.0", + "osenv": "^0.1.5", + "promise-inflight": "^1.0.1", + "promise-retry": "^1.1.1", + "protoduck": "^5.0.1", + "rimraf": "^2.6.2", + "safe-buffer": "^5.1.2", + "semver": "^5.6.0", + "ssri": "^6.0.1", + "tar": "^4.4.10", + "unique-filename": "^1.1.1", + "which": "^1.3.1" + }, + "dependencies": { + "minipass": { + "version": "2.9.0", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + } + } + }, + "parallel-transform": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "cyclist": "~0.2.2", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "path-exists": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "path-is-inside": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "path-key": { + "version": "2.0.1", + "bundled": true, + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "bundled": true, + "dev": true + }, + "performance-now": { + "version": "2.1.0", + "bundled": true, + "dev": true + }, + "pify": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "prepend-http": { + "version": "1.0.4", + "bundled": true, + "dev": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "promise-inflight": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "promise-retry": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "requires": { + "err-code": "^1.0.0", + "retry": "^0.10.0" + }, + "dependencies": { + "retry": { + "version": "0.10.1", + "bundled": true, + "dev": true + } + } + }, + "promzard": { + "version": "0.3.0", + "bundled": true, + "dev": true, + "requires": { + "read": "1" + } + }, + "proto-list": { + "version": "1.2.4", + "bundled": true, + "dev": true + }, + "protoduck": { + "version": "5.0.1", + "bundled": true, + "dev": true, + "requires": { + "genfun": "^5.0.0" + } + }, + "prr": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "psl": { + "version": "1.1.29", + "bundled": true, + "dev": true + }, + "pump": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "bundled": true, + "dev": true, + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "punycode": { + "version": "1.4.1", + "bundled": true, + "dev": true + }, + "qrcode-terminal": { + "version": "0.12.0", + "bundled": true, + "dev": true + }, + "qs": { + "version": "6.5.2", + "bundled": true, + "dev": true + }, + "query-string": { + "version": "6.8.2", + "bundled": true, + "dev": true, + "requires": { + "decode-uri-component": "^0.2.0", + "split-on-first": "^1.0.0", + "strict-uri-encode": "^2.0.0" + } + }, + "qw": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "rc": { + "version": "1.2.7", + "bundled": true, + "dev": true, + "requires": { + "deep-extend": "^0.5.1", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true + } + } + }, + "read": { + "version": "1.0.7", + "bundled": true, + "dev": true, + "requires": { + "mute-stream": "~0.0.4" + } + }, + "read-cmd-shim": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "^4.1.2" + } + }, + "read-installed": { + "version": "4.0.3", + "bundled": true, + "dev": true, + "requires": { + "debuglog": "^1.0.1", + "graceful-fs": "^4.1.2", + "read-package-json": "^2.0.0", + "readdir-scoped-modules": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "slide": "~1.1.3", + "util-extend": "^1.0.1" + } + }, + "read-package-json": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "requires": { + "glob": "^7.1.1", + "graceful-fs": "^4.1.2", + "json-parse-better-errors": "^1.0.1", + "normalize-package-data": "^2.0.0", + "npm-normalize-package-bin": "^1.0.0" + } + }, + "read-package-tree": { + "version": "5.3.1", + "bundled": true, + "dev": true, + "requires": { + "read-package-json": "^2.0.0", + "readdir-scoped-modules": "^1.0.0", + "util-promisify": "^2.1.0" + } + }, + "readable-stream": { + "version": "3.4.0", + "bundled": true, + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdir-scoped-modules": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "graceful-fs": "^4.1.2", + "once": "^1.3.0" + } + }, + "registry-auth-token": { + "version": "3.3.2", + "bundled": true, + "dev": true, + "requires": { + "rc": "^1.1.6", + "safe-buffer": "^5.0.1" + } + }, + "registry-url": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "rc": "^1.0.1" + } + }, + "request": { + "version": "2.88.0", + "bundled": true, + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, + "require-directory": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "resolve-from": { + "version": "4.0.0", + "bundled": true, + "dev": true + }, + "retry": { + "version": "0.12.0", + "bundled": true, + "dev": true + }, + "rimraf": { + "version": "2.6.3", + "bundled": true, + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "run-queue": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^1.1.1" + }, + "dependencies": { + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true + } + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true, + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "dev": true + }, + "semver": { + "version": "5.7.1", + "bundled": true, + "dev": true + }, + "semver-diff": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "semver": "^5.0.3" + } + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "sha": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "^4.1.2" + } + }, + "shebang-command": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true + }, + "slide": { + "version": "1.1.6", + "bundled": true, + "dev": true + }, + "smart-buffer": { + "version": "4.1.0", + "bundled": true, + "dev": true + }, + "socks": { + "version": "2.3.3", + "bundled": true, + "dev": true, + "requires": { + "ip": "1.1.5", + "smart-buffer": "^4.1.0" + } + }, + "socks-proxy-agent": { + "version": "4.0.2", + "bundled": true, + "dev": true, + "requires": { + "agent-base": "~4.2.1", + "socks": "~2.3.2" + }, + "dependencies": { + "agent-base": { + "version": "4.2.1", + "bundled": true, + "dev": true, + "requires": { + "es6-promisify": "^5.0.0" + } + } + } + }, + "sorted-object": { + "version": "2.0.1", + "bundled": true, + "dev": true + }, + "sorted-union-stream": { + "version": "2.1.3", + "bundled": true, + "dev": true, + "requires": { + "from2": "^1.3.0", + "stream-iterate": "^1.1.0" + }, + "dependencies": { + "from2": { + "version": "1.3.0", + "bundled": true, + "dev": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "~1.1.10" + } + }, + "isarray": { + "version": "0.0.1", + "bundled": true, + "dev": true + }, + "readable-stream": { + "version": "1.1.14", + "bundled": true, + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true, + "dev": true + } + } + }, + "spdx-correct": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.1.0", + "bundled": true, + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.3", + "bundled": true, + "dev": true + }, + "split-on-first": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "sshpk": { + "version": "1.14.2", + "bundled": true, + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "ssri": { + "version": "6.0.1", + "bundled": true, + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1" + } + }, + "stream-each": { + "version": "1.2.2", + "bundled": true, + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "stream-iterate": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "readable-stream": "^2.1.5", + "stream-shift": "^1.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "stream-shift": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "strict-uri-encode": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "string-width": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "string_decoder": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "stringify-package": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-eof": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true + }, + "supports-color": { + "version": "5.4.0", + "bundled": true, + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "tar": { + "version": "4.4.13", + "bundled": true, + "dev": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" + }, + "dependencies": { + "minipass": { + "version": "2.9.0", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + } + } + }, + "term-size": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "execa": "^0.7.0" + } + }, + "text-table": { + "version": "0.2.0", + "bundled": true, + "dev": true + }, + "through": { + "version": "2.3.8", + "bundled": true, + "dev": true + }, + "through2": { + "version": "2.0.3", + "bundled": true, + "dev": true, + "requires": { + "readable-stream": "^2.1.5", + "xtend": "~4.0.1" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "timed-out": { + "version": "4.0.1", + "bundled": true, + "dev": true + }, + "tiny-relative-date": { + "version": "1.3.0", + "bundled": true, + "dev": true + }, + "tough-cookie": { + "version": "2.4.3", + "bundled": true, + "dev": true, + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "bundled": true, + "dev": true, + "optional": true + }, + "typedarray": { + "version": "0.0.6", + "bundled": true, + "dev": true + }, + "uid-number": { + "version": "0.0.6", + "bundled": true, + "dev": true + }, + "umask": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "unique-filename": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "unique-string": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "crypto-random-string": "^1.0.0" + } + }, + "unpipe": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "unzip-response": { + "version": "2.0.1", + "bundled": true, + "dev": true + }, + "update-notifier": { + "version": "2.5.0", + "bundled": true, + "dev": true, + "requires": { + "boxen": "^1.2.1", + "chalk": "^2.0.1", + "configstore": "^3.0.0", + "import-lazy": "^2.1.0", + "is-ci": "^1.0.10", + "is-installed-globally": "^0.1.0", + "is-npm": "^1.0.0", + "latest-version": "^3.0.0", + "semver-diff": "^2.0.0", + "xdg-basedir": "^3.0.0" + } + }, + "url-parse-lax": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "prepend-http": "^1.0.1" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "util-extend": { + "version": "1.0.3", + "bundled": true, + "dev": true + }, + "util-promisify": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "object.getownpropertydescriptors": "^2.0.3" + } + }, + "uuid": { + "version": "3.3.3", + "bundled": true, + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "validate-npm-package-name": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "builtins": "^1.0.3" + } + }, + "verror": { + "version": "1.10.0", + "bundled": true, + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "wcwidth": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "defaults": "^1.0.3" + } + }, + "which": { + "version": "1.3.1", + "bundled": true, + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "wide-align": { + "version": "1.1.2", + "bundled": true, + "dev": true, + "requires": { + "string-width": "^1.0.2" + }, + "dependencies": { + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, + "widest-line": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "string-width": "^2.1.1" + } + }, + "worker-farm": { + "version": "1.7.0", + "bundled": true, + "dev": true, + "requires": { + "errno": "~0.1.7" + } + }, + "wrap-ansi": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "write-file-atomic": { + "version": "2.4.3", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "xdg-basedir": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "xtend": { + "version": "4.0.1", + "bundled": true, + "dev": true + }, + "y18n": { + "version": "4.0.0", + "bundled": true, + "dev": true + }, + "yallist": { + "version": "3.0.3", + "bundled": true, + "dev": true + }, + "yargs": { + "version": "11.1.1", + "bundled": true, + "dev": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.1.1", + "find-up": "^2.1.0", + "get-caller-file": "^1.0.1", + "os-locale": "^3.1.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^9.0.2" + }, + "dependencies": { + "y18n": { + "version": "3.2.1", + "bundled": true, + "dev": true + } + } + }, + "yargs-parser": { + "version": "9.0.2", + "bundled": true, + "dev": true, + "requires": { + "camelcase": "^4.1.0" + } + } + } + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "octokit-pagination-methods": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/octokit-pagination-methods/-/octokit-pagination-methods-1.1.0.tgz", + "integrity": "sha512-fZ4qZdQ2nxJvtcasX7Ghl+WlWS/d9IgnBIwFZXVNNZUmzpno91SX5bc5vuxiuKoCtK78XxGGNuSCrDC7xYB3OQ==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "opencollective-postinstall": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.2.tgz", + "integrity": "sha512-pVOEP16TrAO2/fjej1IdOyupJY8KDUM1CvsaScRbw6oddvpQoOfGk4ywha0HKKVAD6RkW4x6Q+tNBwhf3Bgpuw==", + "dev": true + }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + } + }, + "os-name": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-name/-/os-name-3.1.0.tgz", + "integrity": "sha512-h8L+8aNjNcMpo/mAIBPn5PXCM16iyPGjHNWo6U1YO8sJTMHtEtyczI6QJnLoplswm6goopQkqc7OAnjhWcugVg==", + "dev": true, + "requires": { + "macos-release": "^2.2.0", + "windows-release": "^3.1.0" + } + }, + "p-each-series": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.1.0.tgz", + "integrity": "sha512-ZuRs1miPT4HrjFa+9fRfOFXxGJfORgelKV9f9nNOWw2gl6gVsRaVDOQP0+MI0G0wGKns1Yacsu0GjOFbTK0JFQ==", + "dev": true + }, + "p-filter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-2.1.0.tgz", + "integrity": "sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==", + "dev": true, + "requires": { + "p-map": "^2.0.0" + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-is-promise": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-3.0.0.tgz", + "integrity": "sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==", + "dev": true + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "dev": true + }, + "p-reduce": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-2.1.0.tgz", + "integrity": "sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw==", + "dev": true + }, + "p-retry": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.2.0.tgz", + "integrity": "sha512-jPH38/MRh263KKcq0wBNOGFJbm+U6784RilTmHjB/HM9kH9V8WlCpVUcdOmip9cjXOh6MxZ5yk1z2SjDUJfWmA==", + "dev": true, + "requires": { + "@types/retry": "^0.12.0", + "retry": "^0.12.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "parsimmon": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/parsimmon/-/parsimmon-1.13.0.tgz", + "integrity": "sha512-5UIrOCW+gjbILkjKPgTgmq8LKf8TT3Iy7kN2VD7OtQ81facKn8B4gG1X94jWqXYZsxG2KbJhrv/Yq/5H6BQn7A==", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "picomatch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.1.tgz", + "integrity": "sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA==", + "dev": true + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "pkg-conf": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.1.0.tgz", + "integrity": "sha1-ISZRTKbyq/69FoWW3xi6V4Z/AFg=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "load-json-file": "^4.0.0" + } + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", + "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + } + } + }, + "please-upgrade-node": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", + "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==", + "dev": true, + "requires": { + "semver-compare": "^1.0.0" + } + }, + "prettier": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", + "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "promisified-properties": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/promisified-properties/-/promisified-properties-2.0.2.tgz", + "integrity": "sha512-py8yn4zqt5khR+1qmykvy0ecsCTqHQxdJRbKvBqwe736APCvocpDbN4WP0rQA472fehlkHQSHXAvAfEhdlBNBQ==", + "dev": true, + "requires": { + "parsimmon": "^1.13.0" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", + "dev": true + }, + "quick-lru": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-1.1.0.tgz", + "integrity": "sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=", + "dev": true + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "redent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-2.0.0.tgz", + "integrity": "sha1-wbIAe0LVfrE4kHmzyDM2OdXhzKo=", + "dev": true, + "requires": { + "indent-string": "^3.0.0", + "strip-indent": "^2.0.0" + } + }, + "redeyed": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/redeyed/-/redeyed-2.1.1.tgz", + "integrity": "sha1-iYS1gV2ZyyIEacme7v/jiRPmzAs=", + "dev": true, + "requires": { + "esprima": "~4.0.0" + } + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "dev": true + }, + "registry-auth-token": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.1.1.tgz", + "integrity": "sha512-9bKS7nTl9+/A1s7tnPeGrUpRcVY+LUh7bfFgzpndALdPfXQBfQV77rQVtqgUV3ti4vc/Ik81Ex8UJDWDQ12zQA==", + "dev": true, + "requires": { + "rc": "^1.2.8" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "resolve": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz", + "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + }, + "resolve-global": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-global/-/resolve-global-1.0.0.tgz", + "integrity": "sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw==", + "dev": true, + "requires": { + "global-dirs": "^0.1.1" + } + }, + "resolve-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg/-/resolve-pkg-2.0.0.tgz", + "integrity": "sha512-+1lzwXehGCXSeryaISr6WujZzowloigEofRB+dj75y9RRa/obVcYgbHJd53tdYw8pvZj8GojXaaENws8Ktw/hQ==", + "dev": true, + "requires": { + "resolve-from": "^5.0.0" + } + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + }, + "dependencies": { + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + } + } + }, + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "run-parallel": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", + "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", + "dev": true + }, + "rxjs": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz", + "integrity": "sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "semantic-release": { + "version": "17.0.4", + "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-17.0.4.tgz", + "integrity": "sha512-5y9QRSrZtdvACmlpX5DvEVsvFuKRDUVn7JVJFxPVLGrGofDf1d0M/+hA1wFmCjiJZ+VCY8bYaSqVqF14KCF9rw==", + "dev": true, + "requires": { + "@semantic-release/commit-analyzer": "^8.0.0", + "@semantic-release/error": "^2.2.0", + "@semantic-release/github": "^7.0.0", + "@semantic-release/npm": "^7.0.0", + "@semantic-release/release-notes-generator": "^9.0.0", + "aggregate-error": "^3.0.0", + "cosmiconfig": "^6.0.0", + "debug": "^4.0.0", + "env-ci": "^5.0.0", + "execa": "^4.0.0", + "figures": "^3.0.0", + "find-versions": "^3.0.0", + "get-stream": "^5.0.0", + "git-log-parser": "^1.2.0", + "hook-std": "^2.0.0", + "hosted-git-info": "^3.0.0", + "lodash": "^4.17.15", + "marked": "^0.8.0", + "marked-terminal": "^4.0.0", + "micromatch": "^4.0.2", + "p-each-series": "^2.1.0", + "p-reduce": "^2.0.0", + "read-pkg-up": "^7.0.0", + "resolve-from": "^5.0.0", + "semver": "^7.1.1", + "semver-diff": "^3.1.1", + "signale": "^1.2.1", + "yargs": "^15.0.1" + }, + "dependencies": { + "cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "dev": true, + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + } + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "hosted-git-info": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.2.tgz", + "integrity": "sha512-ezZMWtHXm7Eb7Rq4Mwnx2vs79WUx2QmRg3+ZqeGroKzfDO+EprOcgRPYghsOP9JuYBfK18VojmRTGCg8Ma+ktw==", + "dev": true, + "requires": { + "lru-cache": "^5.1.1" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", + "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "parse-json": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", + "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1", + "lines-and-columns": "^1.1.6" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true + } + } + }, + "read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "requires": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + } + }, + "semver": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.1.3.tgz", + "integrity": "sha512-ekM0zfiA9SCBlsKa2X1hxyxiI4L3B6EbVJkkdgQXnSEEaHlGdvyodMruTiulSRWMMB4NeIuYNMC9rTKTz97GxA==", + "dev": true + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + } + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", + "dev": true + }, + "semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "dev": true, + "requires": { + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "semver-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-2.0.0.tgz", + "integrity": "sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw==", + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "signale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/signale/-/signale-1.4.0.tgz", + "integrity": "sha512-iuh+gPf28RkltuJC7W5MRi6XAjTDCAPC/prJUpQoG4vIP3MJZ+GTydVnodXA7pwvTKb2cA0m9OFZW/cdWy/I/w==", + "dev": true, + "requires": { + "chalk": "^2.3.2", + "figures": "^2.0.0", + "pkg-conf": "^2.1.0" + }, + "dependencies": { + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + } + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "slice-ansi": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", + "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "spawn-error-forwarder": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/spawn-error-forwarder/-/spawn-error-forwarder-1.0.0.tgz", + "integrity": "sha1-Gv2Uc46ZmwNG17n8NzvlXgdXcCk=", + "dev": true + }, + "spdx-correct": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "dev": true + }, + "split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "dev": true, + "requires": { + "through": "2" + } + }, + "split2": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-2.2.0.tgz", + "integrity": "sha512-RAb22TG39LhI31MbreBgIuKiIKhVsawfTgEGqKHTK87aG+ul/PB8Sqoi3I7kVdRWiCfrKxK3uo4/YUkpNvhPbw==", + "dev": true, + "requires": { + "through2": "^2.0.2" + }, + "dependencies": { + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + } + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "stream-combiner2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", + "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=", + "dev": true, + "requires": { + "duplexer2": "~0.1.0", + "readable-stream": "^2.0.2" + } + }, + "string-argv": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", + "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==", + "dev": true + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "dev": true, + "requires": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + }, + "strip-indent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz", + "integrity": "sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=", + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "supports-hyperlinks": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz", + "integrity": "sha512-zoE5/e+dnEijk6ASB6/qrK+oYdm2do1hjoLWrqUC/8WEIW1gbxFcKuBof7sW8ArN6e+AYvsE8HBGiVRWL/F5CA==", + "dev": true, + "requires": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", + "dev": true + }, + "temp-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", + "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", + "dev": true + }, + "tempy": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-0.4.0.tgz", + "integrity": "sha512-mKnScm8aXv+cG6l1Nzp6mERGgC4UblbPnSDeQp83JgZ7xqDcnl+7u3+6zXnf1UE7YluDUTEIna1iKYwCSaOk9g==", + "dev": true, + "requires": { + "temp-dir": "^2.0.0", + "type-fest": "^0.10.0", + "unique-string": "^2.0.0" + }, + "dependencies": { + "type-fest": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.10.0.tgz", + "integrity": "sha512-EUV9jo4sffrwlg8s0zDhP0T2WD3pru5Xi0+HTE3zTUmBaZNhfkite9PdSJwdXLwPVW0jnAHT56pZHIOYckPEiw==", + "dev": true + } + } + }, + "text-extensions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", + "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "through2": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", + "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", + "dev": true, + "requires": { + "readable-stream": "2 || 3" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "traverse": { + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz", + "integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=", + "dev": true + }, + "trim-newlines": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-2.0.0.tgz", + "integrity": "sha1-tAPQuRvlDDMd/EuC7s6yLD3hbSA=", + "dev": true + }, + "trim-off-newlines": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz", + "integrity": "sha1-n5up2e+odkw4dpi8v+sshI8RrbM=", + "dev": true + }, + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", + "dev": true + }, + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true + }, + "uglify-js": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.7.7.tgz", + "integrity": "sha512-FeSU+hi7ULYy6mn8PKio/tXsdSXN35lm4KgV2asx00kzrLU9Pi3oAslcJT70Jdj7PHX29gGUPOT6+lXGBbemhA==", + "dev": true, + "optional": true, + "requires": { + "commander": "~2.20.3", + "source-map": "~0.6.1" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "optional": true + } + } + }, + "unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "requires": { + "crypto-random-string": "^2.0.0" + } + }, + "universal-user-agent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-4.0.0.tgz", + "integrity": "sha512-eM8knLpev67iBDizr/YtqkJsF3GK8gzDc6st/WKzrTuPtcsOKW/0IdL4cnMBsU69pOx0otavLWBDGTwg+dB0aA==", + "dev": true, + "requires": { + "os-name": "^3.1.0" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "url-join": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", + "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "which-pm-runs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz", + "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=", + "dev": true + }, + "windows-release": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-3.2.0.tgz", + "integrity": "sha512-QTlz2hKLrdqukrsapKsINzqMgOUpQW268eJ0OaOpJN32h272waxR9fkB9VoWRtK7uKHG5EHJcTXQBD8XZVJkFA==", + "dev": true, + "requires": { + "execa": "^1.0.0" + }, + "dependencies": { + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + } + } + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true + }, + "wrap-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-3.0.1.tgz", + "integrity": "sha1-KIoE2H7aXChuBg3+jxNc6NAH+Lo=", + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "yaml": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.7.2.tgz", + "integrity": "sha512-qXROVp90sb83XtAoqE8bP9RwAkTTZbugRUTm5YeFCBfNRPEp2YzTeqWiz7m5OORHzEvrA/qcGS8hp/E+MMROYw==", + "dev": true, + "requires": { + "@babel/runtime": "^7.6.3" + } + }, + "yargs": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.1.0.tgz", + "integrity": "sha512-T39FNN1b6hCW4SOIk1XyTOWxtXdcen0t+XYrysQmChzSipvhBO8Bj0nK1ozAasdk24dNWuMZvr4k24nz+8HHLg==", + "dev": true, + "requires": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^16.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", + "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "yargs-parser": { + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-16.1.0.tgz", + "integrity": "sha512-H/V41UNZQPkUMIT5h5hiwg4QKIY1RPvoBV4XcjUbRM8Bk2oKqqyZ0DIEbTFZB0XjbtSPG8SAa/0DxCQmiRgzKg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "yargs-parser": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", + "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", + "dev": true, + "requires": { + "camelcase": "^4.1.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..0f5b621d --- /dev/null +++ b/package.json @@ -0,0 +1,44 @@ +{ + "devDependencies": { + "commitlint": "^8.3.5", + "conventional-changelog-conventionalcommits": "^4.2.3", + "gradle-semantic-release-plugin": "1.4.0", + "husky": "^4.2.1", + "lint-staged": "^10.0.7", + "prettier": "^1.19.1", + "semantic-release": "17.0.4" + }, + "scripts": { + "semantic-release": "semantic-release" + }, + "husky": { + "hooks": { + "pre-commit": "gradle/spotless.sh && lint-staged", + "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" + } + }, + "lint-staged": { + "*.md,package.json": [ + "prettier --write" + ] + }, + "release": { + "tagFormat": "${version}", + "plugins": [ + "@semantic-release/commit-analyzer", + "@semantic-release/release-notes-generator", + "gradle-semantic-release-plugin", + [ + "@semantic-release/github", + { + "assets": [ + "build/libs/*.jar" + ] + } + ] + ] + }, + "engines": { + "node": "^12.12.0" + } +} diff --git a/src/functionalTest/groovy/com/github/spotbugs/snom/AndroidFunctionalTest.groovy b/src/functionalTest/groovy/com/github/spotbugs/snom/AndroidFunctionalTest.groovy new file mode 100644 index 00000000..48d05f5c --- /dev/null +++ b/src/functionalTest/groovy/com/github/spotbugs/snom/AndroidFunctionalTest.groovy @@ -0,0 +1,106 @@ +/* + * Copyright 2019 SpotBugs team + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.github.spotbugs.snom + +import org.gradle.internal.impldep.com.google.common.io.Files +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.GradleRunner +import org.gradle.util.GradleVersion +import org.junit.jupiter.api.BeforeEach +import spock.lang.Ignore +import spock.lang.Specification + +import static org.gradle.testkit.runner.TaskOutcome.SUCCESS +import static org.junit.jupiter.api.Assertions.assertEquals + +class AndroidFunctionalTest extends Specification { + File rootDir + File buildFile + String version = System.getProperty('snom.test.functional.gradle', GradleVersion.current().version) + + @BeforeEach + def setup() { + rootDir = Files.createTempDir() + buildFile = new File(rootDir, 'build.gradle') + } + + @Ignore("need to install Android SDK") + def "can generate spotbugsMain depending on classes task"() { + given: "a Gradle project to build an Android app" + GradleRunner runner = + GradleRunner.create() + .withProjectDir(rootDir) + .withPluginClasspath() + .forwardOutput() + .withGradleVersion(version) + + buildFile << """ +buildscript { + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.3' +""" + runner.pluginClasspath.forEach({ file -> + buildFile << """ + classpath '${file.absolutePath}' +""" + }) + buildFile << """ + } +} + +apply plugin: 'com.android.application' +apply plugin: 'com.github.spotbugs' + +repositories { + google() + jcenter() +} + +android { + compileSdkVersion 29 + buildToolsVersion '29.0.2' + buildTypes { + release { + minifyEnabled false + } + } +} +""" + + File sourceDir = rootDir.toPath().resolve("src").resolve("main").resolve("java").toFile() + sourceDir.mkdirs() + File sourceFile = new File(sourceDir, "Foo.java") + sourceFile << """ +public class Foo { + public static void main(String... args) { + System.out.println("Hello, SpotBugs!"); + } +} +""" + + when: "the spotbugsMain task is executed" + BuildResult result = runner + .withArguments(":spotbugsMain") + .withGradleVersion(version) + .build() + + then: "gradle runs spotbugsMain successfully" + assertEquals(SUCCESS, result.task(":spotbugsMain").outcome) + } +} diff --git a/src/functionalTest/groovy/com/github/spotbugs/snom/BasePluginFunctionalTest.groovy b/src/functionalTest/groovy/com/github/spotbugs/snom/BasePluginFunctionalTest.groovy new file mode 100644 index 00000000..f0481e36 --- /dev/null +++ b/src/functionalTest/groovy/com/github/spotbugs/snom/BasePluginFunctionalTest.groovy @@ -0,0 +1,102 @@ +/* + * Copyright 2019 SpotBugs team + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.github.spotbugs.snom + +import org.gradle.internal.impldep.com.google.common.io.Files +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.GradleRunner +import org.gradle.testkit.runner.TaskOutcome +import org.gradle.util.GradleVersion +import org.junit.jupiter.api.BeforeEach +import spock.lang.Specification +import spock.lang.Unroll + +import java.nio.file.Paths + +import static org.gradle.testkit.runner.TaskOutcome.SUCCESS +import static org.junit.jupiter.api.Assertions.assertEquals +import static org.junit.jupiter.api.Assertions.assertTrue + +class BasePluginFunctionalTest extends Specification { + File rootDir + File buildFile + String version = System.getProperty('snom.test.functional.gradle', GradleVersion.current().version) + + @BeforeEach + def setup() { + rootDir = Files.createTempDir() + buildFile = new File(rootDir, 'build.gradle') + buildFile << """ +plugins { + id 'java' + id 'com.github.spotbugs-base' +} + +version = 1.0 + +repositories { + mavenCentral() +} + """ + File sourceDir = rootDir.toPath().resolve("src").resolve("main").resolve("java").toFile() + sourceDir.mkdirs() + File sourceFile = new File(sourceDir, "Foo.java") + sourceFile << """ +public class Foo { + public static void main(String... args) { + System.out.println("Hello, SpotBugs!"); + } +} +""" + } + + def "does not create SpotBugsTask by default"() { + when: + BuildResult result = + GradleRunner.create() + .withProjectDir(rootDir) + .withArguments(":check") + .withPluginClasspath() + .forwardOutput() + .withGradleVersion(version) + .build() + + then: + result.task(":classes").outcome == TaskOutcome.SUCCESS + !result.tasks.contains(":spotbugsMain") + } + + def "can create spotbugsMain task manually"() { + setup: + buildFile << """ +task spotbugsMain(type: com.github.spotbugs.snom.SpotBugsTask) { + dependsOn 'classes' + classDirs = sourceSets.main.output +} +""" + when: + BuildResult result = + GradleRunner.create() + .withProjectDir(rootDir) + .withArguments(":spotbugsMain") + .withPluginClasspath() + .forwardOutput() + .withGradleVersion(version) + .build() + + then: + result.task(":classes").outcome == TaskOutcome.SUCCESS + result.task(":spotbugsMain").outcome == TaskOutcome.SUCCESS + } +} diff --git a/src/functionalTest/groovy/com/github/spotbugs/snom/ExtensionFunctionalTest.groovy b/src/functionalTest/groovy/com/github/spotbugs/snom/ExtensionFunctionalTest.groovy new file mode 100644 index 00000000..21e9d085 --- /dev/null +++ b/src/functionalTest/groovy/com/github/spotbugs/snom/ExtensionFunctionalTest.groovy @@ -0,0 +1,242 @@ +/* + * Copyright 2019 SpotBugs team + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.github.spotbugs.snom + +import org.gradle.internal.impldep.com.google.common.io.Files +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.GradleRunner +import org.gradle.testkit.runner.TaskOutcome +import org.gradle.util.GradleVersion +import org.junit.jupiter.api.BeforeEach +import spock.lang.Specification + +import static org.gradle.testkit.runner.TaskOutcome.SUCCESS +import static org.junit.jupiter.api.Assertions.assertEquals +import static org.junit.jupiter.api.Assertions.assertTrue + +class ExtensionFunctionalTest extends Specification { + File rootDir + File buildFile + String version = System.getProperty('snom.test.functional.gradle', GradleVersion.current().version) + + @BeforeEach + def setup() { + rootDir = Files.createTempDir() + buildFile = new File(rootDir, 'build.gradle') + buildFile << """ +plugins { + id 'java' + id 'com.github.spotbugs' +} + +version = 1.0 + +repositories { + mavenCentral() +} + """ + File sourceDir = rootDir.toPath().resolve("src").resolve("main").resolve("java").toFile() + sourceDir.mkdirs() + File sourceFile = new File(sourceDir, "Foo.java") + sourceFile << """ +public class Foo { + public static void main(String... args) { + System.out.println("Hello, SpotBugs!"); + } +} +""" + } + + def "can use includeFilter"() { + setup: + File filter = new File(rootDir, "include.xml") + buildFile << """ +spotbugs { + includeFilter = file('include.xml') +}""" + filter << """ + +""" + when: + def result = GradleRunner.create() + .withProjectDir(rootDir) + .withArguments('spotbugsMain', '--debug') + .withPluginClasspath() + .withGradleVersion(version) + .build() + + then: + assertEquals(SUCCESS, result.task(":spotbugsMain").outcome) + assertTrue(result.getOutput().contains("-include")) + assertTrue(result.getOutput().contains(filter.getAbsolutePath())) + } + + def "can use excludeFilter"() { + setup: + File filter = new File(rootDir, "exclude.xml") + buildFile << """ +spotbugs { + excludeFilter = file('exclude.xml') +}""" + filter << """ + +""" + when: + def result = GradleRunner.create() + .withProjectDir(rootDir) + .withArguments('spotbugsMain', '--debug') + .withPluginClasspath() + .withGradleVersion(version) + .build() + + then: + assertEquals(SUCCESS, result.task(":spotbugsMain").outcome) + assertTrue(result.getOutput().contains("-exclude")) + assertTrue(result.getOutput().contains(filter.getAbsolutePath())) + } + + def "can use visitors"() { + setup: + buildFile << """ +spotbugs { + visitors = [ 'FindSqlInjection', 'SwitchFallthrough' ] +}""" + when: + def result = GradleRunner.create() + .withProjectDir(rootDir) + .withArguments('spotbugsMain', '--debug') + .withPluginClasspath() + .withGradleVersion(version) + .build() + + then: + assertEquals(SUCCESS, result.task(":spotbugsMain").outcome) + assertTrue(result.getOutput().contains("-visitors, FindSqlInjection,SwitchFallthrough,")) + } + + def "can use omitVisitors"() { + buildFile << """ +spotbugs { + omitVisitors = [ 'FindSqlInjection', 'SwitchFallthrough' ] +}""" + when: + def result = GradleRunner.create() + .withProjectDir(rootDir) + .withArguments('spotbugsMain', '--debug') + .withPluginClasspath() + .withGradleVersion(version) + .build() + + then: + assertEquals(SUCCESS, result.task(":spotbugsMain").outcome) + assertTrue(result.getOutput().contains("-omitVisitors, FindSqlInjection,SwitchFallthrough,")) + } + + def "can use onlyAnalyze"() { + buildFile << """ +spotbugs { + onlyAnalyze = ['com.foobar.MyClass', 'com.foobar.mypkg.*'] +}""" + when: + def result = GradleRunner.create() + .withProjectDir(rootDir) + .withArguments('spotbugsMain', '--debug') + .withPluginClasspath() + .withGradleVersion(version) + .build() + + then: + assertEquals(SUCCESS, result.task(":spotbugsMain").outcome) + assertTrue(result.getOutput().contains("-onlyAnalyze, com.foobar.MyClass,com.foobar.mypkg.*,")) + } + + def "can use extraArgs and jvmArgs"() { + buildFile << """ +spotbugs { + extraArgs = ['-nested:false'] + jvmArgs = ['-Duser.language=ja'] +}""" + when: + def result = GradleRunner.create() + .withProjectDir(rootDir) + .withArguments('spotbugsMain', '--debug') + .withPluginClasspath() + .withGradleVersion(version) + .build() + + then: + assertEquals(SUCCESS, result.task(":spotbugsMain").outcome) + assertTrue(result.getOutput().contains("-nested:false")) + assertTrue(result.getOutput().contains("-Duser.language=ja")) + } + + def "can use maxHeapSize"() { + buildFile << """ +spotbugs { + maxHeapSize = '256m' +}""" + when: + def result = GradleRunner.create() + .withProjectDir(rootDir) + .withArguments('spotbugsMain', '--debug') + .withPluginClasspath() + .withGradleVersion(version) + .build() + + then: + assertEquals(SUCCESS, result.task(":spotbugsMain").outcome) + assertTrue(result.getOutput().contains("-Xmx256m")) + } + + def "can use effort and reportLevel"() { + buildFile << """ +spotbugs { + effort = 'less' + reportLevel = 'high' +}""" + when: + def result = GradleRunner.create() + .withProjectDir(rootDir) + .withArguments('spotbugsMain', '--debug') + .withPluginClasspath() + .withGradleVersion(version) + .build() + + then: + assertEquals(SUCCESS, result.task(":spotbugsMain").outcome) + assertTrue(result.getOutput().contains("-effort:less")) + assertTrue(result.getOutput().contains("-high")) + } + + def "can use toolVersion to set the SpotBugs version"() { + setup: + buildFile << """ +spotbugs { + toolVersion = "4.0.0-beta4" +}""" + when: + BuildResult result = + GradleRunner.create() + .withProjectDir(rootDir) + .withArguments(":spotbugsMain", "--info") + .withPluginClasspath() + .forwardOutput() + .withGradleVersion(version) + .build() + + then: + assertEquals(TaskOutcome.SUCCESS, result.task(":spotbugsMain").outcome) + assertTrue(result.output.contains("SpotBugs 4.0.0-beta4")) + } +} diff --git a/src/functionalTest/groovy/com/github/spotbugs/snom/MultiProjectFunctionalTest.groovy b/src/functionalTest/groovy/com/github/spotbugs/snom/MultiProjectFunctionalTest.groovy new file mode 100644 index 00000000..21735db0 --- /dev/null +++ b/src/functionalTest/groovy/com/github/spotbugs/snom/MultiProjectFunctionalTest.groovy @@ -0,0 +1,152 @@ +/* + * Copyright 2019 SpotBugs team + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.github.spotbugs.snom + +import org.gradle.internal.impldep.com.google.common.io.Files +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.GradleRunner +import org.gradle.testkit.runner.TaskOutcome +import org.gradle.util.GradleVersion +import org.junit.jupiter.api.BeforeEach +import spock.lang.Ignore +import spock.lang.Specification + +import static org.gradle.testkit.runner.TaskOutcome.SUCCESS +import static org.junit.jupiter.api.Assertions.assertEquals +import static org.junit.jupiter.api.Assertions.assertTrue + +class MultiProjectFunctionalTest extends Specification { + File rootDir + File buildFile + String version = System.getProperty('snom.test.functional.gradle', GradleVersion.current().version) + File subBuildFile + + @BeforeEach + def setup() { + rootDir = Files.createTempDir() + buildFile = new File(rootDir, 'build.gradle') + buildFile << """ +plugins { + id 'java' + id 'com.github.spotbugs' +} + """ + + File settings = new File(rootDir, "settings.gradle") + settings << """ +include ':sub' +""" + + File subProject = new File(rootDir, "sub") + + File sourceDir = subProject.toPath().resolve("src").resolve("main").resolve("java").toFile() + sourceDir.mkdirs() + File sourceFile = new File(sourceDir, "Foo.java") + sourceFile << """ +public class Foo { + public static void main(String... args) { + System.out.println("Hello, SpotBugs!"); + } +} +""" + subBuildFile = new File(subProject, "build.gradle") + subBuildFile << """ +apply plugin: 'java' +apply plugin: 'com.github.spotbugs' +version = 1.0 + +repositories { + mavenCentral() +} +""" + } + + def "can create spotbugsMain task depending on classes task"() { + when: + BuildResult result = + GradleRunner.create() + .withProjectDir(rootDir) + .withArguments(":sub:spotbugsMain") + .withPluginClasspath() + .forwardOutput() + .withGradleVersion(version) + .build() + + then: + assertEquals(TaskOutcome.SUCCESS, result.task(":sub:classes").outcome) + assertEquals(TaskOutcome.SUCCESS, result.task(":sub:spotbugsMain").outcome) + } + + def "can use project name of sub project"() { + when: + def result = GradleRunner.create() + .withProjectDir(rootDir) + .withArguments(':sub:spotbugsMain', '--debug') + .withPluginClasspath() + .withGradleVersion(version) + .forwardOutput() + .build() + + then: + assertEquals(SUCCESS, result.task(":sub:spotbugsMain").outcome) + assertTrue(result.output.contains("-projectName, sub (spotbugsMain)")) + } + + @Ignore("Gradle does not support this type of configuration. See https://git.io/JvOVT#issuecomment-580239267") + def "can use toolVersion in subprojects block"() { + setup: + buildFile << """ +subprojects { + spotbugs { + toolVersion = '4.0.0-RC1' + } +} +""" + + when: + def result = GradleRunner.create() + .withProjectDir(rootDir) + .withArguments(':sub:spotbugsMain', '--debug') + .withPluginClasspath() + .withGradleVersion(version) + .forwardOutput() + .build() + + then: + assertEquals(SUCCESS, result.task(":sub:spotbugsMain").outcome) + assertTrue(result.output.contains("SpotBugs 4.0.0-RC1")) + } + + def "can use toolVersion in the subproject"() { + setup: + subBuildFile << """ +spotbugs { + toolVersion = '4.0.0-RC1' +} +""" + + when: + def result = GradleRunner.create() + .withProjectDir(rootDir) + .withArguments(':sub:spotbugsMain', '--debug') + .withPluginClasspath() + .withGradleVersion(version) + .forwardOutput() + .build() + + then: + assertEquals(SUCCESS, result.task(":sub:spotbugsMain").outcome) + assertTrue(result.output.contains("SpotBugs 4.0.0-RC1")) + } +} diff --git a/src/functionalTest/groovy/com/github/spotbugs/snom/ReportFunctionalTest.groovy b/src/functionalTest/groovy/com/github/spotbugs/snom/ReportFunctionalTest.groovy new file mode 100644 index 00000000..3cdd9ac8 --- /dev/null +++ b/src/functionalTest/groovy/com/github/spotbugs/snom/ReportFunctionalTest.groovy @@ -0,0 +1,419 @@ +/* + * Copyright 2019 SpotBugs team + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.github.spotbugs.snom +import org.gradle.internal.impldep.com.google.common.io.Files +import org.gradle.util.GradleVersion +import org.junit.jupiter.api.BeforeEach +import spock.lang.Specification + +import org.gradle.testkit.runner.GradleRunner + +import static org.gradle.testkit.runner.TaskOutcome.SUCCESS +import static org.junit.jupiter.api.Assertions.assertEquals +import static org.junit.jupiter.api.Assertions.assertFalse +import static org.junit.jupiter.api.Assertions.assertNotNull +import static org.junit.jupiter.api.Assertions.assertTrue + +class ReportFunctionalTest extends Specification { + File rootDir + File buildFile + String version = System.getProperty('snom.test.functional.gradle', GradleVersion.current().version) + + @BeforeEach + def setup() { + rootDir = Files.createTempDir() + buildFile = new File(rootDir, 'build.gradle') + buildFile << """ +plugins { + id 'java' + id 'com.github.spotbugs' +} + +version = 1.0 + +repositories { + mavenCentral() +} + """ + File sourceDir = rootDir.toPath().resolve("src").resolve("main").resolve("java").toFile() + sourceDir.mkdirs() + File sourceFile = new File(sourceDir, "Foo.java") + sourceFile << """ +public class Foo { + public static void main(String... args) { + System.out.println("Hello, SpotBugs!"); + } +} +""" + } + + def "do not generate reports by default"() { + when: + def result = GradleRunner.create() + .withProjectDir(rootDir) + .withArguments('spotbugsMain') + .withPluginClasspath() + .withGradleVersion(version) + .build() + + then: + assertEquals(SUCCESS, result.task(":spotbugsMain").outcome) + File reportsDir = rootDir.toPath().resolve("build").resolve("reports").resolve("spotbugs").toFile() + assertFalse(reportsDir.isDirectory()) + } + + def "can generate spotbugs.txt"() { + buildFile << """ +spotbugsMain { + reports { + text.enabled = true + } +}""" + when: + def result = GradleRunner.create() + .withProjectDir(rootDir) + .withArguments('spotbugsMain', '-is') + .withPluginClasspath() + .withGradleVersion(version) + .build() + + then: + assertEquals(SUCCESS, result.task(":spotbugsMain").outcome) + File report = rootDir.toPath().resolve("build").resolve("reports").resolve("spotbugs").resolve("main.txt").toFile() + assertTrue(report.isFile()) + } + + def "can generate spotbugs.txt in configured buildDir"() { + buildFile << """ +spotbugsMain { + reports { + text.enabled = true + } +} +buildDir = 'new-build-dir' +""" + when: + def result = GradleRunner.create() + .withProjectDir(rootDir) + .withArguments('spotbugsMain') + .withPluginClasspath() + .build() + + then: + assertEquals(SUCCESS, result.task(":spotbugsMain").outcome) + File report = rootDir.toPath().resolve("new-build-dir").resolve("reports").resolve("spotbugs").resolve("main.txt").toFile() + assertTrue(report.isFile()) + } + + def "can generate spotbugs.html in configured buildDir"() { + buildFile << """ +spotbugsMain { + reports { + html.enabled = true + } +} +buildDir = 'new-build-dir' +""" + when: + def result = GradleRunner.create() + .withProjectDir(rootDir) + .withArguments('spotbugsMain') + .withPluginClasspath() + .build() + + then: + assertEquals(SUCCESS, result.task(":spotbugsMain").outcome) + File report = rootDir.toPath().resolve("new-build-dir").resolve("reports").resolve("spotbugs").resolve("main.html").toFile() + assertTrue(report.isFile()) + } + + def "can generate spotbugs.xml in configured buildDir"() { + buildFile << """ +spotbugsMain { + reports { + xml.enabled = true + } +} +buildDir = 'new-build-dir' +""" + when: + def result = GradleRunner.create() + .withProjectDir(rootDir) + .withArguments('spotbugsMain') + .withPluginClasspath() + .build() + + then: + assertEquals(SUCCESS, result.task(":spotbugsMain").outcome) + File report = rootDir.toPath().resolve("new-build-dir").resolve("reports").resolve("spotbugs").resolve("main.xml").toFile() + assertTrue(report.isFile()) + } + + def "can generate spotbugs.html"() { + buildFile << """ +spotbugsMain { + reports { + html.enabled = true + } +}""" + when: + def result = GradleRunner.create() + .withProjectDir(rootDir) + .withArguments('spotbugsMain', '--debug') + .withPluginClasspath() + .forwardOutput() + .withGradleVersion(version) + .build() + + then: + assertEquals(SUCCESS, result.task(":spotbugsMain").outcome) + File report = rootDir.toPath().resolve("build").resolve("reports").resolve("spotbugs").resolve("main.html").toFile() + assertTrue(report.isFile()) + assertTrue(result.getOutput().contains("-html,")) + } + + def "can generate spotbugs.html with stylesheet"() { + new File(rootDir, "settings.gradle") << """ +rootProject.name = 'sample-project' +""" + buildFile << """ +// https://github.com/spotbugs/spotbugs-gradle-plugin/issues/107#issue-408724750 +version = '1.2.3' +configurations { spotbugsStylesheets { transitive false } } +dependencies { spotbugsStylesheets 'com.github.spotbugs:spotbugs:3.1.10' } + +spotbugsMain { + reports { + html { + enabled = true + stylesheet = resources.text.fromArchiveEntry(configurations.spotbugsStylesheets, 'fancy-hist.xsl') + } + } +}""" + when: + def result = GradleRunner.create() + .withProjectDir(rootDir) + .withArguments('spotbugsMain', "--debug") + .withPluginClasspath() + .withGradleVersion(version) + .build() + + then: + assertEquals(SUCCESS, result.task(":spotbugsMain").outcome) + File report = rootDir.toPath().resolve("build").resolve("reports").resolve("spotbugs").resolve("main.html").toFile() + assertTrue(report.isFile()) + assertTrue(result.getOutput().contains("-html:")) + // confirm -projectName is working + assertNotNull(report.readLines("utf-8").find({line -> line.contains("sample-project (spotbugsMain)")})) + // confirm -release is working + assertNotNull(report.readLines("utf-8").find({line -> line.contains("1.2.3")})) + } + + def "can generate spotbugs.html with the path of stylesheet"() { + buildFile << """ +// https://github.com/spotbugs/spotbugs-gradle-plugin/issues/107#issue-408724750 +spotbugsMain { + reports { + html { + enabled = true + stylesheet = 'fancy-hist.xsl' + } + } +}""" + when: + def result = GradleRunner.create() + .withProjectDir(rootDir) + .withArguments('spotbugsMain', '--debug') + .withPluginClasspath() + .withGradleVersion(version) + .build() + + then: + assertEquals(SUCCESS, result.task(":spotbugsMain").outcome) + File report = rootDir.toPath().resolve("build").resolve("reports").resolve("spotbugs").resolve("main.html").toFile() + assertTrue(report.isFile()) + assertTrue(result.getOutput().contains("-html:")) + } + + def "can generate spotbugs.xml"() { + buildFile << """ +spotbugsMain { + reports { + xml.enabled = true + } +}""" + when: + def result = GradleRunner.create() + .withProjectDir(rootDir) + .withArguments('spotbugsMain') + .withPluginClasspath() + .withGradleVersion(version) + .build() + + then: + assertEquals(SUCCESS, result.task(":spotbugsMain").outcome) + File report = rootDir.toPath().resolve("build").resolve("reports").resolve("spotbugs").resolve("main.xml").toFile() + assertTrue(report.isFile()) + } + + def "can generate a report in specified reportsDir"() { + buildFile << """ +spotbugs { + reportsDir = file("\$buildDir/spotbugs") +} +spotbugsMain { + reports { + text {} + } +} +""" + when: + def result = GradleRunner.create() + .withProjectDir(rootDir) + .withArguments('spotbugsMain') + .withPluginClasspath() + .withGradleVersion(version) + .build() + + then: + assertEquals(SUCCESS, result.task(":spotbugsMain").outcome) + File reportsDir = rootDir.toPath().resolve("build").resolve("spotbugs").toFile(); + assertTrue(reportsDir.isDirectory()) + File report = reportsDir.toPath().resolve("main.txt").toFile() + assertTrue(report.isFile()) + } + + def "reports error when set unknown report type"() { + buildFile << """ +spotbugsMain { + reports { + unknown.enabled = true + } +}""" + when: + def result = GradleRunner.create() + .withProjectDir(rootDir) + .withArguments('spotbugsMain') + .withPluginClasspath() + .withGradleVersion(version) + .buildAndFail() + + then: + assertTrue(result.getTasks().isEmpty()) + assertTrue(result.getOutput().contains("unknown is invalid as the report name")) + } + + def "can run task by Worker Process"() { + when: + def result = GradleRunner.create() + .withProjectDir(rootDir) + .withArguments('spotbugsMain', '--info') + .withPluginClasspath() + .forwardOutput() + .withGradleVersion(version) + .build() + + then: + assertEquals(SUCCESS, result.task(":spotbugsMain").outcome) + assertTrue(result.getOutput().contains("Running SpotBugs by Gradle Worker...")); + } + + def "can run task by JavaExec by gradle.properties"() { + new File(rootDir, "gradle.properties") << """ +com.github.spotbugs.snom.worker=false +""" + when: + def result = GradleRunner.create() + .withProjectDir(rootDir) + .withArguments('spotbugsMain', '--info') + .withPluginClasspath() + .forwardOutput() + .withGradleVersion(version) + .build() + + then: + assertEquals(SUCCESS, result.task(":spotbugsMain").outcome) + assertTrue(result.getOutput().contains("Running SpotBugs by JavaExec...")) + } + + def "can run task by JavaExec by commandline option"() { + when: + def result = GradleRunner.create() + .withProjectDir(rootDir) + .withArguments('spotbugsMain', '-Pcom.github.spotbugs.snom.worker=false', '--info') + .withPluginClasspath() + .forwardOutput() + .withGradleVersion(version) + .build() + + then: + assertEquals(SUCCESS, result.task(":spotbugsMain").outcome) + assertTrue(result.getOutput().contains("Running SpotBugs by JavaExec...")) + } + + def "does not resolve spotbugs configuration by setting stylesheet"() { + given: + buildFile << """ +spotbugsMain { + reports { + html { + stylesheet = 'fancy-hist.xsl' + } + } +} + +configurations.spotbugs { + exclude group: 'org.slf4j', module: 'slf4j-log4j12' +} +""" + when: + def result = GradleRunner.create() + .withProjectDir(rootDir) + .withArguments('spotbugsMain') + .withPluginClasspath() + .forwardOutput() + .withGradleVersion(version) + .build() + + then: + assertEquals(SUCCESS, result.task(":spotbugsMain").outcome) + } + + def "can use configuration configured via reporting extension"() { + setup: + buildFile << """ +spotbugsMain { + reports { + text.enabled = true + } +} +reporting { + baseDir "\$buildDir/our-reports" +}""" + when: + def result = GradleRunner.create() + .withProjectDir(rootDir) + .withArguments('spotbugsMain') + .withPluginClasspath() + .withGradleVersion(version) + .build() + + then: + assertEquals(SUCCESS, result.task(":spotbugsMain").outcome) + File reportsDir = rootDir.toPath().resolve("build").resolve("our-reports").resolve("spotbugs").toFile(); + assertTrue(reportsDir.isDirectory()) + File report = reportsDir.toPath().resolve("main.txt").toFile() + assertTrue(report.isFile()) + } +} \ No newline at end of file diff --git a/src/functionalTest/groovy/com/github/spotbugs/snom/StandardFunctionalTest.groovy b/src/functionalTest/groovy/com/github/spotbugs/snom/StandardFunctionalTest.groovy new file mode 100644 index 00000000..4ab8d4f6 --- /dev/null +++ b/src/functionalTest/groovy/com/github/spotbugs/snom/StandardFunctionalTest.groovy @@ -0,0 +1,380 @@ +/* + * Copyright 2019 SpotBugs team + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.github.spotbugs.snom + +import org.gradle.internal.impldep.com.google.common.io.Files +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.GradleRunner +import org.gradle.testkit.runner.TaskOutcome +import org.gradle.util.GradleVersion +import org.junit.jupiter.api.BeforeEach +import spock.lang.Specification +import spock.lang.Unroll + +import java.nio.file.Paths + +import static org.gradle.testkit.runner.TaskOutcome.SUCCESS +import static org.junit.jupiter.api.Assertions.assertEquals +import static org.junit.jupiter.api.Assertions.assertTrue + +class StandardFunctionalTest extends Specification { + File rootDir + File buildFile + String version = System.getProperty('snom.test.functional.gradle', GradleVersion.current().version) + + @BeforeEach + def setup() { + rootDir = Files.createTempDir() + buildFile = new File(rootDir, 'build.gradle') + buildFile << """ +plugins { + id 'java' + id 'com.github.spotbugs' +} + +version = 1.0 + +repositories { + mavenCentral() +} + """ + File sourceDir = rootDir.toPath().resolve("src").resolve("main").resolve("java").toFile() + sourceDir.mkdirs() + File sourceFile = new File(sourceDir, "Foo.java") + sourceFile << """ +public class Foo { + public static void main(String... args) { + System.out.println("Hello, SpotBugs!"); + } +} +""" + } + + def "can create spotbugsMain task depending on classes task"() { + when: + BuildResult result = + GradleRunner.create() + .withProjectDir(rootDir) + .withArguments(":spotbugsMain") + .withPluginClasspath() + .forwardOutput() + .withGradleVersion(version) + .build() + + then: + assertEquals(TaskOutcome.SUCCESS, result.task(":classes").outcome) + assertEquals(TaskOutcome.SUCCESS, result.task(":spotbugsMain").outcome) + } + + def "can use the specified SpotBugs version"() { + setup: + buildFile << """ +dependencies { + spotbugs "com.github.spotbugs:spotbugs:4.0.0-beta4" +}""" + when: + BuildResult result = + GradleRunner.create() + .withProjectDir(rootDir) + .withArguments(":spotbugsMain", "--info") + .withPluginClasspath() + .forwardOutput() + .withGradleVersion(version) + .build() + + then: + assertEquals(TaskOutcome.SUCCESS, result.task(":classes").outcome) + assertTrue(result.output.contains("SpotBugs 4.0.0-beta4")) + } + + def "can skip analysis when no class file we have"() { + setup: + File sourceDir = rootDir.toPath().resolve("src").resolve("main").resolve("java").toFile() + File sourceFile = new File(sourceDir, "Foo.java") + sourceFile.delete() + + when: + BuildResult result = + GradleRunner.create() + .withProjectDir(rootDir) + .withArguments(":spotbugsMain") + .withPluginClasspath() + .forwardOutput() + .withGradleVersion(version) + .build() + + then: + assertEquals(TaskOutcome.NO_SOURCE, result.task(":spotbugsMain").outcome) + } + + def "can use effort and reportLevel"() { + buildFile << """ +spotbugsMain { + effort = 'min' + reportLevel = 'high' +}""" + when: + def result = GradleRunner.create() + .withProjectDir(rootDir) + .withArguments('spotbugsMain', '--debug') + .withPluginClasspath() + .withGradleVersion(version) + .build() + + then: + result.task(":spotbugsMain").outcome == SUCCESS + assertTrue(result.getOutput().contains("-effort:min")) + assertTrue(result.getOutput().contains("-high")) + } + + def "can be cancelled by withType(VerificationTask)"() { + buildFile << """ +tasks.withType(VerificationTask).configureEach { + ignoreFailures = true +} +spotbugsMain { + doLast { + print "SpotBugsMain ignores failures? \${ignoreFailures}" + } +} +""" + when: + def result = GradleRunner.create() + .withProjectDir(rootDir) + .withArguments('spotbugsMain') + .withPluginClasspath() + .withGradleVersion(version) + .build() + + then: + assertEquals(SUCCESS, result.task(":spotbugsMain").outcome) + assertTrue(result.getOutput().contains("SpotBugsMain ignores failures? true")) + } + + def "is cache-able"() { + buildFile << """ +spotbugsMain { + reports { + text.enabled = true + } +}""" + + when: + GradleRunner.create() + .withProjectDir(rootDir) + .withArguments(":spotbugsMain") + .withPluginClasspath() + .withGradleVersion(version) + .build() + def result = GradleRunner.create() + .withProjectDir(rootDir) + .withArguments(":spotbugsMain", "--info") + .withPluginClasspath() + .forwardOutput() + .withGradleVersion(version) + .build() + + then: + assertEquals(TaskOutcome.UP_TO_DATE, result.task(":classes").outcome) + assertEquals(TaskOutcome.UP_TO_DATE, result.task(":spotbugsMain").outcome) + } + + @Unroll + def 'build fails when bugs are found (Worker API? #isWorkerApi)'() { + given: + def badCode = new File(rootDir, 'src/main/java/Bar.java') + badCode << ''' + |public class Bar { + | public int unreadField = 42; // warning: URF_UNREAD_FIELD + |} + |'''.stripMargin() + + when: + def arguments = [':spotbugsMain', '-is'] + if(!isWorkerApi) { + arguments.add('-Pcom.github.spotbugs.snom.worker=false') + } + def runner = GradleRunner.create() + .withProjectDir(rootDir) + .withArguments(arguments) + .withPluginClasspath() + .forwardOutput() + .withGradleVersion(version) + + def result = runner.buildAndFail() + + then: + result.task(':spotbugsMain').outcome == TaskOutcome.FAILED + + where: + isWorkerApi << [true, false] + } + + @Unroll + def 'build does not fail when bugs are found with `ignoreFailures = true` (Worker API? #isWorkerApi)'() { + given: + def badCode = new File(rootDir, 'src/main/java/Bar.java') + badCode << ''' + |public class Bar { + | public int unreadField = 42; // warning: URF_UNREAD_FIELD + |} + |'''.stripMargin() + + buildFile << """ +spotbugs { + ignoreFailures = true +}""" + when: + def arguments = [':spotbugsMain', '-is'] + if(!isWorkerApi) { + arguments.add('-Pcom.github.spotbugs.snom.worker=false') + } + def runner = GradleRunner.create() + .withProjectDir(rootDir) + .withArguments(arguments) + .withPluginClasspath() + .forwardOutput() + .withGradleVersion(version) + + def result = runner. build() + + then: + result.task(':spotbugsMain').outcome == TaskOutcome.SUCCESS + + where: + isWorkerApi << [true, false] + } + + def 'PatternFilterable methods can work for classes props'() { + given: + def badCode = new File(rootDir, 'src/main/java/Bar.java') + badCode << ''' + |public class Bar { + | public int unreadField = 42; // warning: URF_UNREAD_FIELD + |} + |'''.stripMargin() + + buildFile << """ +spotbugsMain { + classes = classes.filter { it.name.contains 'Foo' } +}""" + when: + def runner = GradleRunner.create() + .withProjectDir(rootDir) + .withArguments(':spotbugsMain', '-is') + .withPluginClasspath() + .forwardOutput() + .withGradleVersion(version) + + def result = runner. build() + + then: + result.task(':spotbugsMain').outcome == TaskOutcome.SUCCESS + } + def 'analyse main sourceset only'() { + given: + buildFile << """ +tasks.withType(com.github.spotbugs.snom.SpotBugsTask).configureEach { + it.enabled = it.name == 'spotbugsMain' +} +""" + File testDir = rootDir.toPath().resolve("src").resolve("test").resolve("java").toFile() + testDir.mkdirs() + File sourceFile = new File(testDir, "Foo.java") + sourceFile << """ +public class Foo { + public static void main(String... args) { + System.out.println("Hello, SpotBugs!"); + } +} +""" + when: + def runner = GradleRunner.create() + .withProjectDir(rootDir) + .withArguments(':spotbugsMain', ':spotbugsTest') + .withPluginClasspath() + .forwardOutput() + .withGradleVersion(version) + + def result = runner.build() + + then: + TaskOutcome.SUCCESS == result.task(':spotbugsMain').outcome + TaskOutcome.SKIPPED == result.task(':spotbugsTest').outcome + } + + def 'can analyse the sourceSet added by user'() { + given: + buildFile << """ +sourceSets { + another { + java { + srcDir 'src/another' + } + } +} +spotbugsAnother { + reports { + text.enabled = true + } +}""" + File sourceDir = rootDir.toPath().resolve(Paths.get("src", "another", "java")).toFile() + sourceDir.mkdirs() + File sourceFile = new File(sourceDir, "Foo.java") + sourceFile << """ +public class Foo { + public static void main(String... args) { + System.out.println("Hello, SpotBugs!"); + } +} +""" + + when: + def runner = GradleRunner.create() + .withProjectDir(rootDir) + .withArguments(':spotbugsAnother') + .withPluginClasspath() + .forwardOutput() + .withGradleVersion(version) + + def result = runner.build() + + then: + TaskOutcome.SUCCESS == result.task(':spotbugsAnother').outcome + } + + def "can pass the analysis when classDirs contain no .class file"() { + setup: + File sourceDir = rootDir.toPath().resolve("src").resolve("main").resolve("java").toFile() + File sourceFile = new File(sourceDir, "Foo.java") + sourceFile.delete() + File resourceDir = rootDir.toPath().resolve("src").resolve("main").resolve("resources").toFile() + resourceDir.mkdir() + File xml = new File(resourceDir, "bar.xml") + xml << "" + when: + BuildResult result = + GradleRunner.create() + .withProjectDir(rootDir) + .withArguments(":spotbugsMain") + .withPluginClasspath() + .forwardOutput() + .withGradleVersion(version) + .build() + + then: + result.task(":classes").outcome == TaskOutcome.SUCCESS + result.task(":spotbugsMain").outcome == TaskOutcome.NO_SOURCE + } +} diff --git a/src/main/groovy/com/github/spotbugs/snom/Confidence.groovy b/src/main/groovy/com/github/spotbugs/snom/Confidence.groovy new file mode 100644 index 00000000..c4c1f383 --- /dev/null +++ b/src/main/groovy/com/github/spotbugs/snom/Confidence.groovy @@ -0,0 +1,69 @@ +/* + * Copyright 2019 SpotBugs team + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.github.spotbugs.snom; + +import javax.annotation.Nonnull; +import org.gradle.api.tasks.Internal; + +/** + * The {@code Confidence} is used to specify the level to report bugs. Lower level contains more + * bugs reported. To include all bugs to your report, use {@link #LOW}. + * + *

Usage: + * + *

Set via the {@code spotbugs} extension to configure all tasks in your project:

+ * spotbugs {
+ *     reportLevel = 'low'
+ *
+ * + *

Or via {@code SpotBugsTask} to configure the specific task in your project:

+ * spotbugsMain { // or name of another task
+ *     reportLevel = 'high'
+ * }
+ * + *

See also SpotBugs Manual.

+ */ +enum Confidence { + /** The report level to report all detected bugs in the report. */ + LOW { + @Override + String toCommandLineOption() { + return "-low" + } + }, + /** The report level to report medium and high priority detected bugs in the report. */ + MEDIUM { + @Override + String toCommandLineOption() { + return "-medium" + } + }, + /** The default level that provides the same feature with {@link #MEDIUM}. */ + DEFAULT { + @Override + String toCommandLineOption() { + return "" + } + }, + /** The report level to report high priority detected bugs in the report. */ + HIGH { + @Override + String toCommandLineOption() { + return "-high" + } + } + + @Internal("This is internally used property so no need to refer to judge out-of-date or not.") + abstract @Nonnull String toCommandLineOption() +} diff --git a/src/main/groovy/com/github/spotbugs/snom/Effort.groovy b/src/main/groovy/com/github/spotbugs/snom/Effort.groovy new file mode 100644 index 00000000..791ac9c7 --- /dev/null +++ b/src/main/groovy/com/github/spotbugs/snom/Effort.groovy @@ -0,0 +1,54 @@ +/* + * Copyright 2019 SpotBugs team + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.github.spotbugs.snom; + +/** + * The {@code Effort} is configuration to adjust SpotBugs detectors. Use lower effort to reduce + * computation cost. + * + *

Usage: + * + *

Set via the {@code spotbugs} extension to configure all tasks in your project:

+ * spotbugs {
+ *     effort = 'less'
+ * }
+ * + *

Or via {@code SpotBugsTask} to configure the specific task in your project:

+ * spotbugsMain { // or name of another task
+ *     effort = 'max'
+ * }
+ * + *

See also SpotBugs Manual.

+ */ +enum Effort { + /** + * The effort level to minimize the computation cost. SpotBugs will try to conserve space at the + * expense of precision. + */ + MIN, + /** The effort level to reduce the computation cost. */ + LESS, + /** The default level that provides the same feature with {@link #MORE}. */ + DEFAULT, + /** + * The effort level that uses more computation cost. SpotBugs will try to detect more problems by + * Interprocedural Analysis and Null Pointer Analysis. + */ + MORE, + /** + * The effort level that maximize the computation cost. SpotBugs will run Interprocedural Analysis + * of Referenced Classes. + */ + MAX +} diff --git a/src/main/groovy/com/github/spotbugs/snom/SpotBugsBasePlugin.java b/src/main/groovy/com/github/spotbugs/snom/SpotBugsBasePlugin.java new file mode 100644 index 00000000..68ad868d --- /dev/null +++ b/src/main/groovy/com/github/spotbugs/snom/SpotBugsBasePlugin.java @@ -0,0 +1,126 @@ +/* + * Copyright 2019 SpotBugs team + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.github.spotbugs.snom; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.net.URL; +import java.util.Properties; +import org.gradle.api.Plugin; +import org.gradle.api.Project; +import org.gradle.api.artifacts.Configuration; +import org.gradle.api.artifacts.DependencySet; +import org.gradle.api.plugins.ReportingBasePlugin; +import org.gradle.util.GradleVersion; + +public class SpotBugsBasePlugin implements Plugin { + /** + * Supported Gradle version described at official manual site. The Gradle Worker API needs 5.6 or + * later, so we use this value as minimal required version. + */ + private static final GradleVersion SUPPORTED_VERSION = GradleVersion.version("5.6"); + + @Override + public void apply(Project project) { + verifyGradleVersion(GradleVersion.current()); + project.getPluginManager().apply(ReportingBasePlugin.class); + + SpotBugsExtension extension = createExtension(project); + createConfiguration(project, extension); + createPluginConfiguration(project); + project + .getTasks() + .withType(SpotBugsTask.class) + .configureEach( + (task) -> { + task.init(extension); + }); + } + + private SpotBugsExtension createExtension(Project project) { + return project + .getExtensions() + .create( + SpotBugsPlugin.EXTENSION_NAME, SpotBugsExtension.class, project, project.getObjects()); + } + + private void createConfiguration(Project project, SpotBugsExtension extension) { + Properties props = loadProperties(); + extension.getToolVersion().convention(props.getProperty("spotbugs-version")); + + Configuration configuration = + project + .getConfigurations() + .create(SpotBugsPlugin.CONFIG_NAME) + .setDescription("configuration for the SpotBugs engine") + .setVisible(false) + .setTransitive(true); + + configuration.defaultDependencies( + (DependencySet dependencies) -> + dependencies.add( + project + .getDependencies() + .create("com.github.spotbugs:spotbugs:" + extension.getToolVersion().get()))); + + Configuration spotbugsSlf4j = + project + .getConfigurations() + .create(SpotBugsPlugin.SLF4J_CONFIG_NAME) + .setDescription("configuration for the SLF4J provider to run SpotBugs") + .setVisible(false) + .setTransitive(true); + + spotbugsSlf4j.defaultDependencies( + (DependencySet dependencies) -> + dependencies.add( + project + .getDependencies() + .create("org.slf4j:slf4j-simple:" + props.getProperty("slf4j-version")))); + } + + Properties loadProperties() { + URL url = + SpotBugsPlugin.class.getClassLoader().getResource("spotbugs-gradle-plugin.properties"); + try (InputStream input = url.openStream()) { + Properties prop = new Properties(); + prop.load(input); + return prop; + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + private Configuration createPluginConfiguration(Project project) { + return project + .getConfigurations() + .create(SpotBugsPlugin.PLUGINS_CONFIG_NAME) + .setDescription("configuration for the external SpotBugs plugins") + .setVisible(false) + .setTransitive(true); + } + + void verifyGradleVersion(GradleVersion version) { + if (version.compareTo(SUPPORTED_VERSION) < 0) { + String message = + String.format( + "Gradle version %s is unsupported. Please use %s or later.", + version, SUPPORTED_VERSION); + throw new IllegalArgumentException(message); + } + } +} diff --git a/src/main/groovy/com/github/spotbugs/snom/SpotBugsExtension.groovy b/src/main/groovy/com/github/spotbugs/snom/SpotBugsExtension.groovy new file mode 100644 index 00000000..4ac59cd4 --- /dev/null +++ b/src/main/groovy/com/github/spotbugs/snom/SpotBugsExtension.groovy @@ -0,0 +1,197 @@ +/* + * Copyright 2019 SpotBugs team + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.github.spotbugs.snom; + +import edu.umd.cs.findbugs.annotations.NonNull +import edu.umd.cs.findbugs.annotations.Nullable +import org.gradle.api.Action +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.reporting.ReportingExtension + +import javax.inject.Inject; +import org.gradle.api.Project; +import org.gradle.api.model.ObjectFactory; +import org.gradle.api.provider.ListProperty; +import org.gradle.api.provider.Property; + +/** + * The extension to configure the SpotBugs Gradle plugin. Most of properties in this extension will be used as the default property of all {@link SpotBugsTask}. + * All properties are optional. + * + *

Usage: + *

After you apply the SpotBugs Gradle plugin to project, write extension like below:

+ * spotbugs {
+ *     ignoreFailures = false
+ *     showProgress = false
+ *     reportLevel = 'default'
+ *     effort = 'default'
+ *     visitors = [ 'FindSqlInjection', 'SwitchFallthrough' ]
+ *     omitVisitors = [ 'FindNonShortCircuit' ]
+ *     reportsDir = file("$buildDir/reports/spotbugs")
+ *     includeFilter = file('spotbugs-include.xml')
+ *     excludeFilter = file('spotbugs-exclude.xml')
+ *     onlyAnalyze = ['com.foobar.MyClass', 'com.foobar.mypkg.*']
+ *     projectName = name
+ *     release = version
+ *     extraArgs = [ '-nested:false' ]
+ *     jvmArgs = [ '-Duser.language=ja' ]
+ *     maxHeapSize = '512m'
+ *}
+ * + *

See also SpotBugs Manual about configuration.

+ */ +class SpotBugsExtension { + static final String DEFAULT_REPORTS_DIR_NAME = "spotbugs"; + + @NonNull + final Property ignoreFailures; + /** + * Property to enable progress reporting during the analysis. Default value is {@code false}. + */ + @NonNull + final Property showProgress; + /** + * Property to specify the level to report bugs. Default value is {@link Confidence#DEFAULT}. + */ + @NonNull + final Property reportLevel; + /** + * Property to adjust SpotBugs detectors. Default value is {@link Effort#DEFAULT}. + */ + @NonNull + final Property effort; + /** + * Property to enable visitors (detectors) for analysis. Default is empty that means all visitors run analysis. + */ + @NonNull + final ListProperty visitors; + /** + * Property to disable visitors (detectors) for analysis. Default is empty that means SpotBugs omits no visitor. + */ + @NonNull + final ListProperty omitVisitors; + /** + * Property to set the directory to generate report files. Default is {@code "$buildDir/reports/spotbugs"}. + * + *

Note that each {@link SpotBugsTask} creates own sub-directory in this directory.

+ */ + @NonNull + final DirectoryProperty reportsDir; + /** + * Property to set the filter file to limit which bug should be reported. + * + *

Note that this property will NOT limit which bug should be detected. To limit the target classes to analyze, use {@link #onlyAnalyze} instead. + * To limit the visitors (detectors) to run, use {@link #visitors} and {@link #omitVisitors} instead.

+ * + *

See also SpotBugs Manual about Filter file.

+ */ + @NonNull + final RegularFileProperty includeFilter; + /** + * Property to set the filter file to limit which bug should be reported. + * + *

Note that this property will NOT limit which bug should be detected. To limit the target classes to analyze, use {@link #onlyAnalyze} instead. + * To limit the visitors (detectors) to run, use {@link #visitors} and {@link #omitVisitors} instead.

+ * + *

See also SpotBugs Manual about Filter file.

+ */ + @NonNull + final RegularFileProperty excludeFilter; + /** + * Property to specify the target classes for analysis. Default value is empty that means all classes are analyzed. + */ + @NonNull + final ListProperty onlyAnalyze; + /** + * Property to specify the name of project. Some reporting formats use this property. Default value is the name of your Gradle project. + */ + @NonNull + final Property projectName; + /** + * Property to specify the release identifier of project. Some reporting formats use this property. Default value is the version of your Gradle project. + */ + @NonNull + final Property release; + /** + * Property to specify the extra arguments for SpotBugs. Default value is empty so SpotBugs will get no extra argument. + */ + @NonNull + final ListProperty extraArgs; + /** + * Property to specify the extra arguments for JVM process. Default value is empty so JVM process will get no extra argument. + */ + @NonNull + final ListProperty jvmArgs; + /** + * Property to specify the max heap size ({@code -Xmx} option) of JVM process. + * Default value is empty so the default configuration made by Gradle will be used. + */ + @NonNull + final Property maxHeapSize; + + @NonNull + final Property toolVersion + + @Inject + SpotBugsExtension(Project project, ObjectFactory objects) { + ignoreFailures = objects.property(Boolean).convention(false); + showProgress = objects.property(Boolean); + reportLevel = objects.property(Confidence); + effort = objects.property(Effort); + visitors = objects.listProperty(String); + omitVisitors = objects.listProperty(String); + reportsDir = objects.directoryProperty() + includeFilter = objects.fileProperty() + excludeFilter = objects.fileProperty() + onlyAnalyze = objects.listProperty(String); + projectName = objects.property(String); + release = objects.property(String); + configureFromProject(project, { p -> + projectName.convention(p.getName()) + release.convention(p.getVersion().toString()) + }) + + // ReportingBasePlugin should be applied before we create this SpotBugsExtension instance + DirectoryProperty baseReportsDir = project.extensions.getByType(ReportingExtension).baseDirectory + reportsDir = objects.directoryProperty().convention(baseReportsDir.map({ + it.dir(DEFAULT_REPORTS_DIR_NAME) + })) + + jvmArgs = objects.listProperty(String); + extraArgs = objects.listProperty(String); + maxHeapSize = objects.property(String); + toolVersion = objects.property(String) + } + + void setReportLevel(@Nullable String name) { + Confidence confidence = name == null ? null : Confidence.valueOf(name.toUpperCase()) + getReportLevel().set(confidence) + } + + void setEffort(@Nullable String name) { + Effort effort = name == null ? null : Effort.valueOf(name.toUpperCase()) + getEffort().set(effort) + } + + private void configureFromProject(Project project, Action action) { + if (project.state.executed && project.rootProject.state.executed) { + action.execute project + } else if (!project.rootProject.state.executed) { + project.rootProject.afterEvaluate action + } else { + project.afterEvaluate action + } + } +} diff --git a/src/main/groovy/com/github/spotbugs/snom/SpotBugsPlugin.java b/src/main/groovy/com/github/spotbugs/snom/SpotBugsPlugin.java new file mode 100644 index 00000000..29c282aa --- /dev/null +++ b/src/main/groovy/com/github/spotbugs/snom/SpotBugsPlugin.java @@ -0,0 +1,47 @@ +/* + * Copyright 2019 SpotBugs team + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.github.spotbugs.snom; + +import com.github.spotbugs.snom.internal.SpotBugsTaskFactory; +import edu.umd.cs.findbugs.annotations.Nullable; +import org.gradle.api.Plugin; +import org.gradle.api.Project; +import org.gradle.api.Task; + +public class SpotBugsPlugin implements Plugin { + public static final String CONFIG_NAME = "spotbugs"; + public static final String PLUGINS_CONFIG_NAME = "spotbugsPlugins"; + public static final String SLF4J_CONFIG_NAME = "spotbugsSlf4j"; + public static final String EXTENSION_NAME = "spotbugs"; + + @Override + public void apply(Project project) { + project.getPluginManager().apply(SpotBugsBasePlugin.class); + SpotBugsExtension extension = project.getExtensions().findByType(SpotBugsExtension.class); + createTasks(project, extension); + } + + private void createTasks(Project project, SpotBugsExtension extension) { + @Nullable Task check = project.getTasks().findByName("check"); + new SpotBugsTaskFactory() + .generate( + project, + task -> { + if (check != null) { + check.dependsOn(task); + } + task.init(extension); + }); + } +} diff --git a/src/main/groovy/com/github/spotbugs/snom/SpotBugsReport.java b/src/main/groovy/com/github/spotbugs/snom/SpotBugsReport.java new file mode 100644 index 00000000..6a70f198 --- /dev/null +++ b/src/main/groovy/com/github/spotbugs/snom/SpotBugsReport.java @@ -0,0 +1,141 @@ +/* + * Copyright 2019 SpotBugs team + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.github.spotbugs.snom; + +import edu.umd.cs.findbugs.annotations.CheckForNull; +import edu.umd.cs.findbugs.annotations.NonNull; +import groovy.lang.Closure; +import java.io.File; +import java.util.Optional; +import javax.annotation.Nullable; +import javax.inject.Inject; +import org.gradle.api.file.RegularFileProperty; +import org.gradle.api.model.ObjectFactory; +import org.gradle.api.provider.Property; +import org.gradle.api.provider.Provider; +import org.gradle.api.reporting.CustomizableHtmlReport; +import org.gradle.api.reporting.Report; +import org.gradle.api.reporting.SingleFileReport; +import org.gradle.api.resources.TextResource; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.Internal; +import org.gradle.api.tasks.OutputFile; +import org.gradle.util.ConfigureUtil; + +public abstract class SpotBugsReport + implements SingleFileReport, + CustomizableHtmlReport // to expose CustomizableHtmlReport#setStylesheet to build script +{ + private final RegularFileProperty destination; + private final Property isEnabled; + private final Property isRequired; + private final SpotBugsTask task; + + @Inject + public SpotBugsReport(ObjectFactory objects, SpotBugsTask task) { + this.destination = objects.fileProperty(); + this.isEnabled = objects.property(Boolean.class); + this.isRequired = objects.property(Boolean.class).value(Boolean.TRUE); + this.task = task; + } + + @NonNull + public abstract Optional toCommandLineOption(); + + @Override + @OutputFile + public File getDestination() { + return destination.get().getAsFile(); + } + + // @Override // New API from 6.1; see https://github.com/gradle/gradle/issues/11923 + @OutputFile + public RegularFileProperty getOutputLocation() { + return destination; + } + + @Override + @Internal("This property returns always same value") + public OutputType getOutputType() { + return OutputType.FILE; + } + + // @Override // New API from 6.1; see https://github.com/gradle/gradle/issues/11923 + @Input + public Property getRequired() { + return isRequired; + } + + @Override + @Input + public boolean isEnabled() { + return isEnabled.getOrElse(Boolean.TRUE); + } + + @Override + public void setEnabled(boolean b) { + isEnabled.set(b); + } + + @Override + public void setEnabled(Provider provider) { + isEnabled.set(provider); + } + + @Override + public void setDestination(File file) { + destination.set(file); + } + + @Override + public void setDestination(Provider provider) { + destination.set(this.task.getProject().getLayout().file(provider)); + } + + @Override + public Report configure(Closure closure) { + ConfigureUtil.configureSelf(closure, this); + return this; + } + + @Override + @Internal("This property provides only a human readable name.") + public String getDisplayName() { + return String.format("%s type report generated by the task %s", getName(), getTask().getPath()); + } + + @CheckForNull + @Override + // TODO adding an @Input triggers 'cannot be serialized' exception + public TextResource getStylesheet() { + return null; + } + + @Override + public void setStylesheet(@Nullable TextResource textResource) { + throw new UnsupportedOperationException( + String.format("stylesheet property is not available in the %s type report", getName())); + } + + public void setStylesheet(@Nullable String path) { + throw new UnsupportedOperationException( + String.format("stylesheet property is not available in the %s type report", getName())); + } + + @NonNull + @Internal + protected final SpotBugsTask getTask() { + return task; + } +} diff --git a/src/main/groovy/com/github/spotbugs/snom/SpotBugsTask.groovy b/src/main/groovy/com/github/spotbugs/snom/SpotBugsTask.groovy new file mode 100644 index 00000000..e16ccd6c --- /dev/null +++ b/src/main/groovy/com/github/spotbugs/snom/SpotBugsTask.groovy @@ -0,0 +1,400 @@ +/* + * Copyright 2019 SpotBugs team + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.github.spotbugs.snom; + +import com.github.spotbugs.snom.internal.SpotBugsHtmlReport; +import com.github.spotbugs.snom.internal.SpotBugsRunnerForJavaExec; +import com.github.spotbugs.snom.internal.SpotBugsRunnerForWorker; +import com.github.spotbugs.snom.internal.SpotBugsTextReport; +import com.github.spotbugs.snom.internal.SpotBugsXmlReport; +import edu.umd.cs.findbugs.annotations.NonNull +import edu.umd.cs.findbugs.annotations.Nullable; +import edu.umd.cs.findbugs.annotations.OverrideMustInvoke +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.provider.Provider; +import org.gradle.api.tasks.SkipWhenEmpty + +import org.gradle.api.Action; +import org.gradle.api.DefaultTask; +import org.gradle.api.InvalidUserDataException; +import org.gradle.api.NamedDomainObjectContainer; +import org.gradle.api.artifacts.Configuration; +import org.gradle.api.file.FileCollection; +import org.gradle.api.model.ObjectFactory; +import org.gradle.api.provider.ListProperty; +import org.gradle.api.provider.Property; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.InputFile; +import org.gradle.api.tasks.InputFiles; +import org.gradle.api.tasks.Internal; +import org.gradle.api.tasks.Nested; +import org.gradle.api.tasks.Optional; +import org.gradle.api.tasks.PathSensitive; +import org.gradle.api.tasks.PathSensitivity; +import org.gradle.api.tasks.TaskAction +import org.gradle.api.tasks.VerificationTask; +import org.gradle.util.ClosureBackedAction; +import org.gradle.workers.WorkerExecutor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory + +import javax.inject.Inject + +/** + * The Gradle task to run the SpotBugs analysis. All properties are optional. + * + *

Usage for Java project: + *

After you apply the SpotBugs Gradle plugin to project, {@code SpotBugsTask} is automatically + * generated for each sourceSet. If you want to configure generated tasks, write build scripts like below:

+ * spotbugsMain {
+ *     sourceDirs = sourceSets.main.allSource.srcDirs
+ *     classDirs = sourceSets.main.output
+ *     auxClassPaths = sourceSets.main.compileClasspath
+ *
+ *     ignoreFailures = false
+ *     showProgress = false
+ *     reportLevel = 'default'
+ *     effort = 'default'
+ *     visitors = [ 'FindSqlInjection', 'SwitchFallthrough' ]
+ *     omitVisitors = [ 'FindNonShortCircuit' ]
+ *     reportsDir = file("$buildDir/reports/spotbugs")
+ *     includeFilter = file('spotbugs-include.xml')
+ *     excludeFilter = file('spotbugs-exclude.xml')
+ *     onlyAnalyze = ['com.foobar.MyClass', 'com.foobar.mypkg.*']
+ *     projectName = name
+ *     release = version
+ *     extraArgs = [ '-nested:false' ]
+ *     jvmArgs = [ '-Duser.language=ja' ]
+ *     maxHeapSize = '512m'
+ *}
+ * + *

See also SpotBugs Manual about configuration.

+ */ +class SpotBugsTask extends DefaultTask implements VerificationTask { + private static final String FEATURE_FLAG_WORKER_API = "com.github.spotbugs.snom.worker"; + private final Logger log = LoggerFactory.getLogger(SpotBugsTask); + + private final WorkerExecutor workerExecutor; + + @NonNull final Property ignoreFailures; + /** + * Property to enable progress reporting during the analysis. Default value is {@code false}. + */ + @Input + @Optional + @NonNull + final Property showProgress; + /** + * Property to specify the level to report bugs. Default value is {@link Confidence#DEFAULT}. + */ + @Input + @Optional + @NonNull + final Property reportLevel; + /** + * Property to adjust SpotBugs detectors. Default value is {@link Effort#DEFAULT}. + */ + @Input + @Optional + @NonNull + final Property effort; + /** + * Property to enable visitors (detectors) for analysis. Default is empty that means all visitors run analysis. + */ + @Input + @NonNull + final ListProperty visitors; + /** + * Property to disable visitors (detectors) for analysis. Default is empty that means SpotBugs omits no visitor. + */ + @Input + @NonNull + final ListProperty omitVisitors; + + /** + * Property to set the directory to generate report files. Default is {@code "$buildDir/reports/spotbugs/$taskName"}. + */ + @Internal("Refer the destination of each report instead.") + @NonNull + final DirectoryProperty reportsDir; + + /** + * Property to specify which report you need. + * + * @see SpotBugsReport + */ + @Internal + @NonNull + final NamedDomainObjectContainer reports; + + /** + * Property to set the filter file to limit which bug should be reported. + * + *

Note that this property will NOT limit which bug should be detected. To limit the target classes to analyze, use {@link #onlyAnalyze} instead. + * To limit the visitors (detectors) to run, use {@link #visitors} and {@link #omitVisitors} instead.

+ * + *

See also SpotBugs Manual about Filter file.

+ */ + @Optional + @InputFile + @PathSensitive(PathSensitivity.RELATIVE) + @NonNull + final RegularFileProperty includeFilter; + /** + * Property to set the filter file to limit which bug should be reported. + * + *

Note that this property will NOT limit which bug should be detected. To limit the target classes to analyze, use {@link #onlyAnalyze} instead. + * To limit the visitors (detectors) to run, use {@link #visitors} and {@link #omitVisitors} instead.

+ * + *

See also SpotBugs Manual about Filter file.

+ */ + @Optional + @InputFile + @PathSensitive(PathSensitivity.RELATIVE) + @NonNull + final RegularFileProperty excludeFilter; + /** + * Property to specify the target classes for analysis. Default value is empty that means all classes are analyzed. + */ + @Input + @NonNull + final ListProperty onlyAnalyze; + /** + * Property to specify the name of project. Some reporting formats use this property. + * Default value is {@code "${project.name} (${task.name})"}. + */ + @Input + @NonNull + final Property projectName; + /** + * Property to specify the release identifier of project. Some reporting formats use this property. Default value is the version of your Gradle project. + */ + @Input + @NonNull + final Property release; + /** + * Property to specify the extra arguments for SpotBugs. Default value is empty so SpotBugs will get no extra argument. + */ + @Optional + @Input + @NonNull + final ListProperty extraArgs; + /** + * Property to specify the extra arguments for JVM process. Default value is empty so JVM process will get no extra argument. + */ + @Optional + @Input + @NonNull + final ListProperty jvmArgs; + /** + * Property to specify the max heap size ({@code -Xmx} option) of JVM process. + * Default value is empty so the default configuration made by Gradle will be used. + */ + @Optional + @Input + @NonNull + final Property maxHeapSize; + /** + * Property to specify the directories that contain the source of target classes to analyze. + * Default value is the source directory of the target sourceSet. + */ + @InputFiles + @PathSensitive(PathSensitivity.RELATIVE) + FileCollection sourceDirs; + + /** + * Property to specify the directories that contains the target classes to analyze. + * Default value is the output directory of the target sourceSet. + */ + @Internal + FileCollection classDirs; + + /** + * Property to specify the aux class paths that contains the libraries to refer during analysis. + * Default value is the compile-scope dependencies of the target sourceSet. + */ + @InputFiles + @PathSensitive(PathSensitivity.RELATIVE) + FileCollection auxClassPaths; + + private FileCollection classes; + + void setClasses(FileCollection fileCollection) { + this.classes = fileCollection + } + + /** + * Property to specify the target classes to analyse by SpotBugs. + * Default value is the all existing {@code .class} files in {@link #getClassDirs}. + */ + @InputFiles + @PathSensitive(PathSensitivity.RELATIVE) + @SkipWhenEmpty + @NonNull + FileCollection getClasses() { + if (classes == null) { + if (getClassDirs() == null) { + throw new InvalidUserDataException("The classDirs property is not set") + } + return getClassDirs().asFileTree.filter({ File file -> + file.name.endsWith(".class") + }) + } else { + return classes + } + } + + @Inject + SpotBugsTask(ObjectFactory objects, WorkerExecutor workerExecutor) { + this.workerExecutor = Objects.requireNonNull(workerExecutor); + + sourceDirs = objects.fileCollection() + auxClassPaths = objects.fileCollection() + ignoreFailures = objects.property(Boolean) + showProgress = objects.property(Boolean); + reportLevel = objects.property(Confidence); + effort = objects.property(Effort); + visitors = objects.listProperty(String); + omitVisitors = objects.listProperty(String); + reportsDir = objects.directoryProperty() + reports = + objects.domainObjectContainer( + SpotBugsReport, {name -> + switch (name) { + case "html": + return objects.newInstance(SpotBugsHtmlReport.class, objects, this) + case "xml": + return objects.newInstance(SpotBugsXmlReport.class, objects, this) + case "text": + return objects.newInstance(SpotBugsTextReport.class, objects, this) + default: + throw new InvalidUserDataException(name + " is invalid as the report name"); + } + }); + includeFilter = objects.fileProperty() + excludeFilter = objects.fileProperty() + onlyAnalyze = objects.listProperty(String); + projectName = objects.property(String); + release = objects.property(String); + jvmArgs = objects.listProperty(String); + extraArgs = objects.listProperty(String); + maxHeapSize = objects.property(String); + } + + /** + * Set properties from extension right after the task creation. User may overwrite these + * properties by build script. + * + * @param extension the source extension to copy the properties. + */ + void init(SpotBugsExtension extension) { + ignoreFailures.convention(extension.ignoreFailures) + showProgress.convention(extension.showProgress) + reportLevel.convention(extension.reportLevel) + effort.convention(extension.effort) + visitors.convention(extension.visitors) + omitVisitors.convention(extension.omitVisitors) + // the default reportsDir is "$buildDir/reports/spotbugs/" + reportsDir.convention(extension.reportsDir) + includeFilter.convention(extension.includeFilter) + excludeFilter.convention(extension.excludeFilter) + onlyAnalyze.convention(extension.onlyAnalyze) + projectName.convention(extension.projectName.map({p -> String.format("%s (%s)", p, getName())})) + release.convention(extension.release) + jvmArgs.convention(extension.jvmArgs) + extraArgs.convention(extension.extraArgs) + maxHeapSize.convention(extension.maxHeapSize) + } + + @TaskAction + void run() { + if (getProject().hasProperty(FEATURE_FLAG_WORKER_API) + && getProject() + .property(FEATURE_FLAG_WORKER_API) + .toString() == "false") { + log.info("Running SpotBugs by JavaExec..."); + new SpotBugsRunnerForJavaExec().run(this); + } else { + log.info("Running SpotBugs by Gradle Worker..."); + new SpotBugsRunnerForWorker(workerExecutor).run(this); + } + } + + final NamedDomainObjectContainer reports( + Closure> closure) { + return reports( + new ClosureBackedAction>(closure)) + } + + final NamedDomainObjectContainer reports( + Action> configureAction) { + configureAction.execute(reports) + return reports + } + + @NonNull + @Internal + Set getPluginJar() { + return getProject().getConfigurations().getByName(SpotBugsPlugin.PLUGINS_CONFIG_NAME).getFiles() + } + + @NonNull + @Internal + FileCollection getSpotbugsClasspath() { + Configuration config = getProject().getConfigurations().getByName(SpotBugsPlugin.CONFIG_NAME) + Configuration spotbugsSlf4j = getProject().getConfigurations().getByName(SpotBugsPlugin.SLF4J_CONFIG_NAME) + + return getProject().files(config, spotbugsSlf4j) + } + + @Nullable + @Optional + @Nested + SpotBugsReport getFirstEnabledReport() { + return reports.stream().filter({report -> report.enabled}).findFirst().orElse(null) + } + + void setReportLevel(@Nullable String name) { + Confidence confidence = name == null ? null : Confidence.valueOf(name.toUpperCase()) + getReportLevel().set(confidence) + } + + void setEffort(@Nullable String name) { + Effort effort = name == null ? null : Effort.valueOf(name.toUpperCase()) + getEffort().set(effort) + } + + void setIgnoreFailures(Provider b) { + ignoreFailures.set(b); + } + + void setIgnoreFailures(boolean b) { + ignoreFailures.set(b); + } + + @Input + boolean getIgnoreFailures() { + ignoreFailures.get(); + } + + @Internal + String getBaseName() { + String prunedName = name.replaceFirst("spotbugs", "") + if (prunedName.isEmpty()) { + prunedName = task.getName() + } + return new StringBuilder().append(Character.toLowerCase(prunedName.charAt(0))).append(prunedName.substring(1)).toString() + } +} diff --git a/src/main/groovy/com/github/spotbugs/snom/internal/SpotBugsHtmlReport.java b/src/main/groovy/com/github/spotbugs/snom/internal/SpotBugsHtmlReport.java new file mode 100644 index 00000000..928a68f7 --- /dev/null +++ b/src/main/groovy/com/github/spotbugs/snom/internal/SpotBugsHtmlReport.java @@ -0,0 +1,101 @@ +/* + * Copyright 2019 SpotBugs team + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.github.spotbugs.snom.internal; + +import com.github.spotbugs.snom.SpotBugsReport; +import com.github.spotbugs.snom.SpotBugsTask; +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; +import java.io.File; +import java.util.Optional; +import javax.inject.Inject; +import org.gradle.api.InvalidUserDataException; +import org.gradle.api.file.RegularFile; +import org.gradle.api.model.ObjectFactory; +import org.gradle.api.provider.Property; +import org.gradle.api.resources.TextResource; + +public abstract class SpotBugsHtmlReport extends SpotBugsReport { + private final Property stylesheet; + private final Property stylesheetPath; + + @Inject + public SpotBugsHtmlReport(ObjectFactory objects, SpotBugsTask task) { + super(objects, task); + // the default reportsDir is "$buildDir/reports/spotbugs/${baseName}.html" + setDestination( + task.getReportsDir().file(task.getBaseName() + ".html").map(RegularFile::getAsFile)); + stylesheet = objects.property(TextResource.class); + stylesheetPath = objects.property(String.class); + } + + @NonNull + @Override + public Optional toCommandLineOption() { + @Nullable TextResource stylesheet = getStylesheet(); + + if (stylesheet == null) { + return Optional.of("-html"); + } else { + return Optional.of("-html:" + getStylesheet().asFile().getAbsolutePath()); + } + } + + @Override + public String getName() { + return "HTML"; + } + + @Override + public TextResource getStylesheet() { + if (stylesheet.isPresent()) { + return stylesheet.get(); + } else if (stylesheetPath.isPresent()) { + return resolve(stylesheetPath.get()); + } + + return null; + } + + private TextResource resolve(String path) { + Optional spotbugsJar = + getTask().getProject().getConfigurations().getByName("spotbugs") + .files( + dependency -> + dependency.getGroup().equals("com.github.spotbugs") + && dependency.getName().equals("spotbugs")) + .stream() + .findFirst(); + if (spotbugsJar.isPresent()) { + return getTask() + .getProject() + .getResources() + .getText() + .fromArchiveEntry(spotbugsJar.get(), path); + } else { + throw new InvalidUserDataException( + "The dependency on SpotBugs not found in 'spotbugs' configuration"); + } + } + + @Override + public void setStylesheet(@Nullable TextResource textResource) { + stylesheet.set(textResource); + } + + @Override + public void setStylesheet(@Nullable String path) { + stylesheetPath.set(path); + } +} diff --git a/src/main/groovy/com/github/spotbugs/snom/internal/SpotBugsRunner.java b/src/main/groovy/com/github/spotbugs/snom/internal/SpotBugsRunner.java new file mode 100644 index 00000000..dad2a3c9 --- /dev/null +++ b/src/main/groovy/com/github/spotbugs/snom/internal/SpotBugsRunner.java @@ -0,0 +1,135 @@ +/* + * Copyright 2019 SpotBugs team + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.github.spotbugs.snom.internal; + +import com.github.spotbugs.snom.SpotBugsReport; +import com.github.spotbugs.snom.SpotBugsTask; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import org.gradle.api.GradleException; +import org.gradle.api.file.FileCollection; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class SpotBugsRunner { + private final Logger log = LoggerFactory.getLogger(SpotBugsRunner.class); + + public abstract void run(@NonNull SpotBugsTask task); + + protected List buildArguments(SpotBugsTask task) { + List args = new ArrayList<>(); + + Set plugins = task.getPluginJar(); + if (!plugins.isEmpty()) { + args.add("-pluginList"); + args.add(join(plugins)); + } + + args.add("-sortByClass"); + args.add("-timestampNow"); + if (!task.getAuxClassPaths().isEmpty()) { + args.add("-auxclasspath"); + args.add(join(task.getAuxClassPaths().getFiles())); + } + if (!task.getSourceDirs().isEmpty()) { + args.add("-sourcepath"); + args.add(task.getSourceDirs().getAsPath()); + } + if (task.getShowProgress().getOrElse(Boolean.FALSE)) { + args.add("-progress"); + } + + SpotBugsReport report = task.getFirstEnabledReport(); + if (report != null) { + File dir = report.getDestination().getParentFile(); + dir.mkdirs(); + report.toCommandLineOption().ifPresent(args::add); + args.add("-outputFile"); + args.add(report.getDestination().getAbsolutePath()); + } + + if (task.getEffort().isPresent()) { + args.add("-effort:" + task.getEffort().get().name().toLowerCase()); + } + if (task.getReportLevel().isPresent()) { + args.add(task.getReportLevel().get().toCommandLineOption()); + } + if (task.getVisitors().isPresent() && !task.getVisitors().get().isEmpty()) { + args.add("-visitors"); + args.add(task.getVisitors().get().stream().collect(Collectors.joining(","))); + } + if (task.getOmitVisitors().isPresent() && !task.getOmitVisitors().get().isEmpty()) { + args.add("-omitVisitors"); + args.add(task.getOmitVisitors().get().stream().collect(Collectors.joining(","))); + } + if (task.getIncludeFilter().isPresent() && task.getIncludeFilter().get() != null) { + args.add("-include"); + args.add(task.getIncludeFilter().get().getAsFile().getAbsolutePath()); + } + if (task.getExcludeFilter().isPresent() && task.getExcludeFilter().get() != null) { + args.add("-exclude"); + args.add(task.getExcludeFilter().get().getAsFile().getAbsolutePath()); + } + if (task.getOnlyAnalyze().isPresent() && !task.getOnlyAnalyze().get().isEmpty()) { + args.add("-onlyAnalyze"); + args.add(task.getOnlyAnalyze().get().stream().collect(Collectors.joining(","))); + } + + args.add("-projectName"); + args.add(task.getProjectName().get()); + args.add("-release"); + args.add(task.getRelease().get()); + args.add("-analyzeFromFile"); + args.add(generateFile(task.getClasses()).getAbsolutePath()); + + args.addAll(task.getExtraArgs().getOrElse(Collections.emptyList())); + log.debug("Arguments for SpotBugs are generated: {}", args); + return args; + } + + private File generateFile(FileCollection files) { + try { + File file = File.createTempFile("spotbugs-gradle-plugin", ".txt"); + Iterable lines = + files.filter(File::exists).getFiles().stream().map(File::getAbsolutePath)::iterator; + Files.write(file.toPath(), lines, StandardCharsets.UTF_8, StandardOpenOption.WRITE); + + return file; + } catch (IOException e) { + throw new GradleException("Fail to generate the text file to list target .class files", e); + } + } + + protected List buildJvmArguments(SpotBugsTask task) { + List args = task.getJvmArgs().getOrElse(Collections.emptyList()); + log.debug("Arguments for JVM process are generated: {}", args); + return args; + } + + private String join(Collection files) { + return files.stream() + .map(File::getAbsolutePath) + .collect(Collectors.joining(File.pathSeparator)); + } +} diff --git a/src/main/groovy/com/github/spotbugs/snom/internal/SpotBugsRunnerForJavaExec.java b/src/main/groovy/com/github/spotbugs/snom/internal/SpotBugsRunnerForJavaExec.java new file mode 100644 index 00000000..eb7896ea --- /dev/null +++ b/src/main/groovy/com/github/spotbugs/snom/internal/SpotBugsRunnerForJavaExec.java @@ -0,0 +1,59 @@ +/* + * Copyright 2019 SpotBugs team + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.github.spotbugs.snom.internal; + +import com.github.spotbugs.snom.SpotBugsTask; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.ArrayList; +import java.util.List; +import org.gradle.api.Action; +import org.gradle.api.GradleException; +import org.gradle.process.JavaExecSpec; +import org.gradle.process.internal.ExecException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SpotBugsRunnerForJavaExec extends SpotBugsRunner { + private final Logger log = LoggerFactory.getLogger(SpotBugsRunnerForJavaExec.class); + + @Override + public void run(@NonNull SpotBugsTask task) { + // TODO print version of SpotBugs and Plugins + try { + task.getProject().javaexec(configureJavaExec(task)).rethrowFailure().assertNormalExitValue(); + } catch (ExecException e) { + if (task.getIgnoreFailures()) { + log.warn("SpotBugs reported failures", e); + } else { + throw new GradleException("Verification failed: SpotBugs execution thrown exception", e); + } + } + } + + private Action configureJavaExec(SpotBugsTask task) { + return spec -> { + List args = new ArrayList<>(); + args.add("-exitcode"); + args.addAll(buildArguments(task)); + spec.classpath(task.getSpotbugsClasspath()); + spec.setJvmArgs(buildJvmArguments(task)); + spec.setMain("edu.umd.cs.findbugs.FindBugs2"); + spec.setArgs(args); + String maxHeapSize = task.getMaxHeapSize().getOrNull(); + if (maxHeapSize != null) { + spec.setMaxHeapSize(maxHeapSize); + } + }; + } +} diff --git a/src/main/groovy/com/github/spotbugs/snom/internal/SpotBugsRunnerForWorker.java b/src/main/groovy/com/github/spotbugs/snom/internal/SpotBugsRunnerForWorker.java new file mode 100644 index 00000000..0486c3a1 --- /dev/null +++ b/src/main/groovy/com/github/spotbugs/snom/internal/SpotBugsRunnerForWorker.java @@ -0,0 +1,107 @@ +/* + * Copyright 2019 SpotBugs team + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.github.spotbugs.snom.internal; + +import com.github.spotbugs.snom.SpotBugsTask; +import edu.umd.cs.findbugs.FindBugs; +import edu.umd.cs.findbugs.FindBugs2; +import edu.umd.cs.findbugs.TextUICommandLine; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Objects; +import org.gradle.api.Action; +import org.gradle.api.GradleException; +import org.gradle.api.provider.ListProperty; +import org.gradle.api.provider.Property; +import org.gradle.workers.ProcessWorkerSpec; +import org.gradle.workers.WorkAction; +import org.gradle.workers.WorkParameters; +import org.gradle.workers.WorkQueue; +import org.gradle.workers.WorkerExecutor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SpotBugsRunnerForWorker extends SpotBugsRunner { + private final WorkerExecutor workerExecutor; + + public SpotBugsRunnerForWorker(@NonNull WorkerExecutor workerExecutor) { + this.workerExecutor = Objects.requireNonNull(workerExecutor); + } + + @Override + public void run(@NonNull SpotBugsTask task) { + Objects.requireNonNull(task); + + WorkQueue workerQueue = workerExecutor.processIsolation(configureWorkerSpec(task)); + workerQueue.submit(SpotBugsExecutor.class, configureWorkParameters(task)); + } + + private Action configureWorkerSpec(SpotBugsTask task) { + return spec -> { + spec.getClasspath().setFrom(task.getSpotbugsClasspath()); + spec.forkOptions( + option -> { + option.jvmArgs(buildJvmArguments(task)); + String maxHeapSize = task.getMaxHeapSize().getOrNull(); + if (maxHeapSize != null) { + option.setMaxHeapSize(maxHeapSize); + } + }); + }; + } + + private Action configureWorkParameters(SpotBugsTask task) { + return params -> { + params.getArguments().addAll(buildArguments(task)); + params.getIgnoreFailures().set(task.getIgnoreFailures()); + }; + } + + interface SpotBugsWorkParameters extends WorkParameters { + ListProperty getArguments(); + + Property getIgnoreFailures(); + } + + public abstract static class SpotBugsExecutor implements WorkAction { + private final Logger log = LoggerFactory.getLogger(SpotBugsExecutor.class); + + @Override + public void execute() { + SpotBugsWorkParameters params = getParameters(); + String[] args = params.getArguments().get().toArray(new String[0]); + + try { + edu.umd.cs.findbugs.Version.printVersion(false); + try (FindBugs2 findBugs2 = new FindBugs2()) { + TextUICommandLine commandLine = new TextUICommandLine(); + FindBugs.processCommandLine(commandLine, args, findBugs2); + findBugs2.execute(); + if (findBugs2.getErrorCount() > 0) { + throw new GradleException( + "Verification failed: SpotBugs error found: " + findBugs2.getErrorCount()); + } else if (findBugs2.getBugCount() > 0) { + throw new GradleException( + "Verification failed: SpotBugs violation found: " + findBugs2.getBugCount()); + } + } + } catch (Exception e) { + if (params.getIgnoreFailures().getOrElse(Boolean.FALSE)) { + log.warn("SpotBugs reported failures", e); + } else { + throw new GradleException("Verification failed: SpotBugs execution thrown exception", e); + } + } + } + } +} diff --git a/src/main/groovy/com/github/spotbugs/snom/internal/SpotBugsTaskFactory.java b/src/main/groovy/com/github/spotbugs/snom/internal/SpotBugsTaskFactory.java new file mode 100644 index 00000000..c64b9184 --- /dev/null +++ b/src/main/groovy/com/github/spotbugs/snom/internal/SpotBugsTaskFactory.java @@ -0,0 +1,93 @@ +/* + * Copyright 2019 SpotBugs team + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.github.spotbugs.snom.internal; + +import com.android.build.gradle.tasks.AndroidJavaCompile; +import com.github.spotbugs.snom.SpotBugsTask; +import org.gradle.api.Action; +import org.gradle.api.Project; +import org.gradle.api.plugins.JavaBasePlugin; +import org.gradle.api.plugins.JavaPluginConvention; +import org.gradle.util.GUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SpotBugsTaskFactory { + private final Logger log = LoggerFactory.getLogger(SpotBugsTaskFactory.class); + + public void generate(Project project, Action configurationAction) { + generateForJava(project, configurationAction); + generateForAndroid(project, configurationAction); + } + + private void generateForJava(Project project, Action configurationAction) { + project + .getPlugins() + .withType(JavaBasePlugin.class) + .configureEach( + javaBasePlugin -> { + JavaPluginConvention convention = + project.getConvention().getPlugin(JavaPluginConvention.class); + convention + .getSourceSets() + .all( + sourceSet -> { + String name = sourceSet.getTaskName("spotbugs", null); + log.debug("Creating SpotBugsTaskForJava for {}", sourceSet); + project + .getTasks() + .register( + name, + SpotBugsTask.class, + task -> { + task.setSourceDirs( + sourceSet.getAllSource().getSourceDirectories()); + task.setClassDirs(sourceSet.getOutput()); + task.setAuxClassPaths(sourceSet.getCompileClasspath()); + configurationAction.execute(task); + }); + }); + }); + } + + private void generateForAndroid( + Project project, Action configurationAction) { + project + .getPlugins() + .withId( + "com.android.application", + plugin -> { + project + .getTasks() + .withType(AndroidJavaCompile.class) + .all( + task -> { + String name = GUtil.toLowerCamelCase("spotbugs " + task.getVariantName()); + log.debug("Creating SpotBugsTaskForAndroid for {}", task); + project + .getTasks() + .register( + name, + SpotBugsTask.class, + spotbugsTask -> { + spotbugsTask.setSourceDirs(task.getSource()); + spotbugsTask.setClassDirs( + task.getOutputDirectory().getAsFileTree()); + spotbugsTask.setAuxClassPaths(task.getClasspath()); + configurationAction.execute(spotbugsTask); + }); + }); + }); + } +} diff --git a/src/main/groovy/com/github/spotbugs/snom/internal/SpotBugsTextReport.java b/src/main/groovy/com/github/spotbugs/snom/internal/SpotBugsTextReport.java new file mode 100644 index 00000000..29d9d4b7 --- /dev/null +++ b/src/main/groovy/com/github/spotbugs/snom/internal/SpotBugsTextReport.java @@ -0,0 +1,49 @@ +/* + * Copyright 2019 SpotBugs team + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.github.spotbugs.snom.internal; + +import com.github.spotbugs.snom.SpotBugsReport; +import com.github.spotbugs.snom.SpotBugsTask; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; +import javax.inject.Inject; +import org.gradle.api.file.RegularFile; +import org.gradle.api.model.ObjectFactory; + +public abstract class SpotBugsTextReport extends SpotBugsReport { + + @Inject + public SpotBugsTextReport(ObjectFactory objects, SpotBugsTask task) { + super(objects, task); + // the default reportsDir is "$buildDir/reports/spotbugs/${baseName}.txt" + setDestination( + task.getReportsDir().file(task.getBaseName() + ".txt").map(RegularFile::getAsFile)); + } + + @NonNull + @Override + public Optional toCommandLineOption() { + return Optional.empty(); + } + + @Override + public String getName() { + return "TEXT"; + } + + @Override + public String getDisplayName() { + return String.format("Text type report generated by the task %s", getTask().getPath()); + } +} diff --git a/src/main/groovy/com/github/spotbugs/snom/internal/SpotBugsXmlReport.java b/src/main/groovy/com/github/spotbugs/snom/internal/SpotBugsXmlReport.java new file mode 100644 index 00000000..322cb148 --- /dev/null +++ b/src/main/groovy/com/github/spotbugs/snom/internal/SpotBugsXmlReport.java @@ -0,0 +1,49 @@ +/* + * Copyright 2019 SpotBugs team + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.github.spotbugs.snom.internal; + +import com.github.spotbugs.snom.SpotBugsReport; +import com.github.spotbugs.snom.SpotBugsTask; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Optional; +import javax.inject.Inject; +import org.gradle.api.file.RegularFile; +import org.gradle.api.model.ObjectFactory; + +public abstract class SpotBugsXmlReport extends SpotBugsReport { + + @Inject + public SpotBugsXmlReport(ObjectFactory objects, SpotBugsTask task) { + super(objects, task); + // the default reportsDir is "$buildDir/reports/spotbugs/${baseName}.xml" + setDestination( + task.getReportsDir().file(task.getBaseName() + ".xml").map(RegularFile::getAsFile)); + } + + @NonNull + @Override + public Optional toCommandLineOption() { + return Optional.of("-xml:withMessages"); + } + + @Override + public String getName() { + return "XML"; + } + + @Override + public String getDisplayName() { + return String.format("XML type report generated by the task %s", getTask().getPath()); + } +} diff --git a/src/main/groovy/com/github/spotbugs/snom/internal/package-info.java b/src/main/groovy/com/github/spotbugs/snom/internal/package-info.java new file mode 100644 index 00000000..2f775704 --- /dev/null +++ b/src/main/groovy/com/github/spotbugs/snom/internal/package-info.java @@ -0,0 +1,19 @@ +/** + * Copyright 2019 SpotBugs team + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * This package provides internal classes/interfaces. All published classes/interfaces/methods in + * this package are NOT treated as public, so it will not keep backward compatibility. It is + * strongly recommended to stop depending on them in your build script. + */ +package com.github.spotbugs.snom.internal; diff --git a/src/main/groovy/com/github/spotbugs/snom/package-info.java b/src/main/groovy/com/github/spotbugs/snom/package-info.java new file mode 100644 index 00000000..e0bac48c --- /dev/null +++ b/src/main/groovy/com/github/spotbugs/snom/package-info.java @@ -0,0 +1,21 @@ +/** + * Copyright 2019 SpotBugs team + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * This package provides public classes/interfaces for users. All published + * classes/interfaces/methods in this package (not including sub-packages) are treated as public and + * keep compatible. + * + *

The {@code SNOM} stands for {@code SpotBugs Newly Organized Mechanism}. + */ +package com.github.spotbugs.snom; diff --git a/src/main/java/com/github/spotbugs/SpotBugsExtension.java b/src/main/java/com/github/spotbugs/SpotBugsExtension.java deleted file mode 100644 index beb5a599..00000000 --- a/src/main/java/com/github/spotbugs/SpotBugsExtension.java +++ /dev/null @@ -1,313 +0,0 @@ -package com.github.spotbugs; - -import java.io.File; -import java.util.Collection; - -import org.gradle.api.Incubating; -import org.gradle.api.Project; -import org.gradle.api.plugins.quality.CodeQualityExtension; -import org.gradle.api.resources.TextResource; - -/** - * Configuration options for the SpotBugs plugin. All options have sensible defaults. - * See the SpotBugs Manual for additional - * information on these options. - * - *

Below is a full configuration example. Since all properties have sensible defaults, - * typically only selected properties will be configured. - * - * apply plugin: "java" - * apply plugin: "spotbugs" - * - * spotbugs { - * toolVersion = "2.0.1" - * sourceSets = [sourceSets.main] - * ignoreFailures = true - * reportsDir = file("$project.buildDir/spotbugsReports") - * effort = "max" - * reportLevel = "high" - * visitors = ["FindSqlInjection", "SwitchFallthrough"] - * omitVisitors = ["FindNonShortCircuit"] - * includeFilter = file("$rootProject.projectDir/config/spotbugs/includeFilter.xml") - * excludeFilter = file("$rootProject.projectDir/config/spotbugs/excludeFilter.xml") - * excludeBugsFilter = file("$rootProject.projectDir/config/spotbugs/excludeBugsFilter.xml") - * showProgress = true - * } - * - * @see SpotBugsPlugin - */ -public class SpotBugsExtension extends CodeQualityExtension { - - private final Project project; - - private String effort; - private String reportLevel; - private Collection visitors; - private Collection omitVisitors; - private TextResource includeFilterConfig; - private TextResource excludeFilterConfig; - private TextResource excludeBugsFilterConfig; - private Collection extraArgs; - private Collection jvmArgs; - private boolean showProgress; - - public SpotBugsExtension(Project project) { - this.project = project; - } - - /** - * The analysis effort level. The value specified should be one of {@code min}, {@code default}, or {@code max}. - * Higher levels increase precision and find more bugs at the expense of running time and memory consumption. - * - * @return analysis effort level - */ - public String getEffort() { - return effort; - } - - /** - * @param effort - * analysis effort level - */ - public void setEffort(String effort) { - this.effort = effort; - } - - /** - * The priority threshold for reporting bugs. If set to {@code low}, all bugs are reported. If set to {@code medium} - * (the default), medium and high priority bugs are reported. If set to {@code high}, only high priority bugs are - * reported. - * - * @return priority threshold for reporting bugs - */ - public String getReportLevel() { - return reportLevel; - } - - /** - * @param reportLevel - * priority threshold for reporting bugs - */ - public void setReportLevel(String reportLevel) { - this.reportLevel = reportLevel; - } - - /** - * The bug detectors which should be run. The bug detectors are specified by their class names, without any package - * qualification. By default, all detectors which are not disabled by default are run. - * - * @return bug detectors which should be run - */ - public Collection getVisitors() { - return visitors; - } - - /** - * @param visitors - * bug detectors which should be run - */ - public void setVisitors(Collection visitors) { - this.visitors = visitors; - } - - /** - * Similar to {@code visitors} except that it specifies bug detectors which should not be run. By default, no - * visitors are omitted. - * - * @return bug detectors which should not be run - */ - public Collection getOmitVisitors() { - return omitVisitors; - } - - /** - * @param omitVisitors - * bug detectors which should not be run - */ - public void setOmitVisitors(Collection omitVisitors) { - this.omitVisitors = omitVisitors; - } - - /** - * A filter specifying which bugs are reported. Replaces the {@code includeFilter} property. - * - * @return filter specifying which bugs are reported - * - * @since 2.2 - */ - @Incubating - public TextResource getIncludeFilterConfig() { - return includeFilterConfig; - } - - @Incubating - public void setIncludeFilterConfig(TextResource includeFilterConfig) { - this.includeFilterConfig = includeFilterConfig; - } - - /** - * The filename of a filter specifying which bugs are reported. - * - * @return filename of a filter specifying which bugs are reported - */ - public File getIncludeFilter() { - TextResource config = getIncludeFilterConfig(); - if (config == null) { - return null; - } - return config.asFile(); - } - - /** - * The filename of a filter specifying which bugs are reported. - * - * @param filter - * filename of a filter specifying which bugs are reported - */ - public void setIncludeFilter(File filter) { - setIncludeFilterConfig(project.getResources().getText().fromFile(filter)); - } - - /** - * A filter specifying bugs to exclude from being reported. Replaces the {@code excludeFilter} property. - * - * @return filter specifying bugs to exclude from being reported - * - * @since 2.2 - */ - @Incubating - public TextResource getExcludeFilterConfig() { - return excludeFilterConfig; - } - - /** - * @param excludeFilterConfig - * filter specifying bugs to exclude from being reported - */ - @Incubating - public void setExcludeFilterConfig(TextResource excludeFilterConfig) { - this.excludeFilterConfig = excludeFilterConfig; - } - - /** - * The filename of a filter specifying bugs to exclude from being reported. - * - * @return filename of a filter specifying bugs to exclude from being reported - */ - public File getExcludeFilter() { - TextResource config = getExcludeFilterConfig(); - if (config == null) { - return null; - } - return config.asFile(); - } - - /** - * The filename of a filter specifying bugs to exclude from being reported. - * - * @param filter - * filename of a filter specifying bugs to exclude from being reported - */ - public void setExcludeFilter(File filter) { - setExcludeFilterConfig(project.getResources().getText().fromFile(filter)); - } - - /** - * A filter specifying baseline bugs to exclude from being reported. - * - * @return filter specifying baseline bugs to exclude from being report - * - * @since 2.4 - */ - @Incubating - public TextResource getExcludeBugsFilterConfig() { - return excludeBugsFilterConfig; - } - - /** - * @param excludeBugsFilterConfig - * filter specifying baseline bugs to exclude from being report - */ - @Incubating - public void setExcludeBugsFilterConfig(TextResource excludeBugsFilterConfig) { - this.excludeBugsFilterConfig = excludeBugsFilterConfig; - } - - /** - * The filename of a filter specifying baseline bugs to exclude from being reported. - * - * @return filename of a filter specifying baseline bugs to exclude from being reporte - */ - public File getExcludeBugsFilter() { - TextResource config = getExcludeBugsFilterConfig(); - if (config == null) { - return null; - } - return config.asFile(); - } - - /** - * The filename of a filter specifying baseline bugs to exclude from being reported. - * - * @param filter - * filename of a filter specifying baseline bugs to exclude from being reported - */ - public void setExcludeBugsFilter(File filter) { - setExcludeBugsFilterConfig(project.getResources().getText().fromFile(filter)); - } - - /** - * Any additional arguments (not covered here more explicitly like {@code effort}) to be passed along to SpotBugs. - *

- * Extra arguments are passed to SpotBugs after the arguments Gradle understands (like {@code effort} but before the - * list of classes to analyze. This should only be used for arguments that cannot be provided by Gradle directly. - * Gradle does not try to interpret or validate the arguments before passing them to SpotBugs. - *

- * See the SpotBugs - * TextUICommandLine source for available options. - * - * @return any additional arguments (not covered here more explicitly like {@code effort}) to be passed along to - * SpotBugs - * - * @since 2.6 - */ - public Collection getExtraArgs() { - return extraArgs; - } - - /** - * @param extraArgs - * any additional arguments (not covered here more explicitly like {@code effort}) to be passed along to - * SpotBugs - */ - public void setExtraArgs(Collection extraArgs) { - this.extraArgs = extraArgs; - } - - public Collection getJvmArgs() { - return jvmArgs; - } - - public void setJvmArgs(Collection jvmArgs) { - this.jvmArgs = jvmArgs; - } - - /** - * Indicates whether analysis progress should be rendered on standard output. Defaults to false. - * - * @return {@code true} if analysis progress should be rendered on standard output. - */ - public boolean isShowProgress() { - return showProgress; - } - - /** - * Indicates whether analysis progress should be rendered on standard output. - * - * @param showProgress Whether progress should be rendered on standard output. - */ - public void setShowProgress(boolean showProgress) { - this.showProgress = showProgress; - } -} diff --git a/src/main/java/com/github/spotbugs/SpotBugsPlugin.java b/src/main/java/com/github/spotbugs/SpotBugsPlugin.java deleted file mode 100644 index 5831103c..00000000 --- a/src/main/java/com/github/spotbugs/SpotBugsPlugin.java +++ /dev/null @@ -1,209 +0,0 @@ -package com.github.spotbugs; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.UncheckedIOException; -import java.net.URL; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; -import java.util.concurrent.Callable; - -import org.gradle.api.artifacts.Configuration; -import org.gradle.api.artifacts.DependencySet; -import org.gradle.api.file.FileCollection; -import org.gradle.api.internal.ConventionMapping; -import org.gradle.api.plugins.quality.CodeQualityExtension; -import org.gradle.api.plugins.quality.internal.AbstractCodeQualityPlugin; -import org.gradle.api.reporting.SingleFileReport; -import org.gradle.api.tasks.SourceSet; -import org.gradle.util.GradleVersion; - -/** - * A plugin for the SpotBugs byte code analyzer. - * - *

- * Declares a spotbugs configuration which needs to be configured with the SpotBugs library to be used. - * Additional plugins can be added to the spotbugsPlugins configuration. - * - *

- * For projects that have the Java (base) plugin applied, a {@link SpotBugsTask} task is - * created for each source set. - * - * @see SpotBugsTask - * @see SpotBugsExtension - */ -public class SpotBugsPlugin extends AbstractCodeQualityPlugin { - - /** - * Supported Gradle version described at official - * manual site. - * - * Package-protected access is for testing purposes - */ - static final GradleVersion SUPPORTED_VERSION = GradleVersion.version("5.2"); - - private SpotBugsExtension extension; - - @Override - protected String getToolName() { - return "SpotBugs"; - } - - @Override - protected Class getTaskType() { - return SpotBugsTask.class; - } - - @Override - protected void beforeApply() { - verifyGradleVersion(GradleVersion.current()); - configureSpotBugsConfigurations(); - } - - /** - * Verify that given version is supported by {@link SpotBugsPlugin} or not. - * - * @param version - * to verify - * @throws IllegalArgumentException - * if given version is not supported - */ - void verifyGradleVersion(GradleVersion version) throws IllegalArgumentException { - if (version.compareTo(SUPPORTED_VERSION) < 0) { - String message = String.format("Gradle version %s is unsupported. Please use %s or later.", version, - SUPPORTED_VERSION); - throw new IllegalArgumentException(message); - } - } - - private void configureSpotBugsConfigurations() { - Configuration configuration = project.getConfigurations().create("spotbugsPlugins"); - configuration.setVisible(false); - configuration.setTransitive(true); - configuration.setDescription("The SpotBugs plugins to be used for this project."); - } - - @Override - protected CodeQualityExtension createExtension() { - extension = project.getExtensions().create("spotbugs", SpotBugsExtension.class, project); - extension.setToolVersion(loadToolVersion()); - return extension; - } - - String loadToolVersion() { - return loadVersion("spotbugs-version"); - } - - String loadSlf4jVersion() { - return loadVersion("slf4j-version"); - } - - private String loadVersion(String name) { - URL url = SpotBugsPlugin.class.getClassLoader().getResource("spotbugs-gradle-plugin.properties"); - try (InputStream input = url.openStream()) { - Properties prop = new Properties(); - prop.load(input); - return prop.getProperty(name); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - @Override - protected void configureTaskDefaults(SpotBugsTask task, String baseName) { - task.setPluginClasspath(project.getConfigurations().getAt("spotbugsPlugins")); - Configuration configuration = project.getConfigurations().getAt("spotbugs"); - configureDefaultDependencies(configuration); - configureTaskConventionMapping(configuration, task); - configureReportsConventionMapping(task, baseName); - } - - protected void configureConfiguration(Configuration configuration) { - // For an abstract method that was newly defined from v4.8, we need an empty method at here - // https://github.com/spotbugs/spotbugs-gradle-plugin/issues/22 - } - - /** - * Overriding this method, to include SLF4J into {@code spotbugsClasspath}. SLF4J is necessary in worker process. - */ - @Override - protected void createConfigurations() { - Configuration configuration = project.getConfigurations().create(getConfigurationName()); - configuration.setVisible(false); - configuration.setTransitive(true); - configuration.setDescription("The " + getToolName() + " libraries to be used for this project."); - // Don't need these things, they're provided by the runtime - configuration.exclude(excludeProperties("ant", "ant")); - configuration.exclude(excludeProperties("org.apache.ant", "ant")); - configuration.exclude(excludeProperties("org.apache.ant", "ant-launcher")); - configuration.exclude(excludeProperties("org.slf4j", "jcl-over-slf4j")); - configuration.exclude(excludeProperties("org.slf4j", "log4j-over-slf4j")); - configuration.exclude(excludeProperties("commons-logging", "commons-logging")); - configuration.exclude(excludeProperties("log4j", "log4j")); - configureConfiguration(configuration); - } - - private Map excludeProperties(String group, String module) { - Map map = new HashMap<>(); - map.put("group", group); - map.put("module", module); - return map; - } - private void configureDefaultDependencies(Configuration configuration) { - configuration.defaultDependencies((DependencySet dependencies) -> { - dependencies.add(project.getDependencies().create("org.slf4j:slf4j-simple:" + loadSlf4jVersion())); - dependencies.add(project.getDependencies().create("com.github.spotbugs:spotbugs:" + extension.getToolVersion())); - }); - } - - private void configureTaskConventionMapping(Configuration configuration, SpotBugsTask task) { - ConventionMapping taskMapping = task.getConventionMapping(); - taskMapping.map("spotbugsClasspath", () -> configuration); - taskMapping.map("ignoreFailures", extension::isIgnoreFailures); - taskMapping.map("effort", extension::getEffort); - taskMapping.map("reportLevel", extension::getReportLevel); - taskMapping.map("visitors", extension::getVisitors); - taskMapping.map("omitVisitors", extension::getOmitVisitors); - - taskMapping.map("excludeFilterConfig", extension::getExcludeFilterConfig); - taskMapping.map("includeFilterConfig", extension::getIncludeFilterConfig); - taskMapping.map("excludeBugsFilterConfig", extension::getExcludeBugsFilterConfig); - - taskMapping.map("extraArgs", extension::getExtraArgs); - taskMapping.map("showProgress", extension::isShowProgress); - - taskMapping.map("jvmArgs", extension::getJvmArgs); - } - - private void configureReportsConventionMapping(SpotBugsTask task, final String baseName) { - task.getReports().all((final SingleFileReport report) -> { - ConventionMapping reportMapping = conventionMappingOf(report); - reportMapping.map("enabled", () -> report.getName().equals("xml")); - reportMapping.map("destination", () -> new File(extension.getReportsDir(), baseName + "." + report.getName())); - }); - } - - @Override - protected void configureForSourceSet(final SourceSet sourceSet, SpotBugsTask task) { - task.setDescription("Run SpotBugs analysis for " + sourceSet.getName() + " classes"); - task.setSourceSet(sourceSet); - ConventionMapping taskMapping = task.getConventionMapping(); - taskMapping.map("classes", (Callable) () -> { - /* - * As a result of the changes made in gradle 4.0. - * See https://docs.gradle.org/4.0/release-notes.html - Location of classes in the build directory - * Compile no longer bundles all classes in one directory build-gradle/classes/main - * but instead separates classes into build-gradle/classes/{language}/main. - * - * We must therefor retrieve all output directories. Filter away the once that don't exist. Add each - * existing file tree dependency to specified task. And then return the complete fileCollection, contain - * all .class files available for analysis. - */ - FileCollection presentClassDirs = sourceSet.getOutput().getClassesDirs().filter(File::exists); - return presentClassDirs.getAsFileTree(); - }); - taskMapping.map("classpath", sourceSet::getRuntimeClasspath); - } -} diff --git a/src/main/java/com/github/spotbugs/SpotBugsReports.java b/src/main/java/com/github/spotbugs/SpotBugsReports.java deleted file mode 100644 index bdd10291..00000000 --- a/src/main/java/com/github/spotbugs/SpotBugsReports.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.github.spotbugs; - -import org.gradle.api.reporting.ReportContainer; -import org.gradle.api.reporting.SingleFileReport; -import org.gradle.api.tasks.Internal; - -/** - * The reporting configuration for the {@link SpotBugsTask} task. - * - * Only one of the reports can be enabled when the task executes. If more than one is enabled, an {@link org.gradle.api.InvalidUserDataException} - * will be thrown. - */ -public interface SpotBugsReports extends ReportContainer { - - /** - * The spotbugs XML report - * - * @return The spotbugs XML report - */ - @Internal - SpotBugsXmlReport getXml(); - - /** - * The spotbugs HTML report - * - * @return The spotbugs HTML report - */ - @Internal - SingleFileReport getHtml(); - - /** - * The spotbugs Text report - * - * @return The spotbugs Text report - */ - @Internal - SingleFileReport getText(); - - /** - * The spotbugs Emacs report - * - * @return The spotbugs Emacs report - */ - @Internal - SingleFileReport getEmacs(); -} \ No newline at end of file diff --git a/src/main/java/com/github/spotbugs/SpotBugsTask.java b/src/main/java/com/github/spotbugs/SpotBugsTask.java deleted file mode 100644 index 727671b7..00000000 --- a/src/main/java/com/github/spotbugs/SpotBugsTask.java +++ /dev/null @@ -1,728 +0,0 @@ -package com.github.spotbugs; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Set; -import java.util.stream.Collectors; - -import javax.inject.Inject; - -import org.gradle.api.Action; -import org.gradle.api.GradleException; -import org.gradle.api.Incubating; -import org.gradle.api.InvalidUserDataException; -import org.gradle.api.JavaVersion; -import org.gradle.api.file.FileCollection; -import org.gradle.api.file.FileTree; -import org.gradle.api.logging.LogLevel; -import org.gradle.api.reporting.Reporting; -import org.gradle.api.reporting.SingleFileReport; -import org.gradle.api.resources.TextResource; -import org.gradle.api.tasks.CacheableTask; -import org.gradle.api.tasks.Classpath; -import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.InputFiles; -import org.gradle.api.tasks.Internal; -import org.gradle.api.tasks.Nested; -import org.gradle.api.tasks.Optional; -import org.gradle.api.tasks.PathSensitive; -import org.gradle.api.tasks.PathSensitivity; -import org.gradle.api.tasks.SkipWhenEmpty; -import org.gradle.api.tasks.SourceSet; -import org.gradle.api.tasks.SourceTask; -import org.gradle.api.tasks.TaskAction; -import org.gradle.api.tasks.VerificationTask; -import org.gradle.internal.logging.ConsoleRenderer; -import org.gradle.internal.reflect.Instantiator; -import org.gradle.process.internal.worker.WorkerProcessFactory; -import org.gradle.util.ConfigureUtil; - -import com.github.spotbugs.internal.SpotBugsReportsImpl; -import com.github.spotbugs.internal.SpotBugsReportsInternal; -import com.github.spotbugs.internal.spotbugs.SpotBugsClasspathValidator; -import com.github.spotbugs.internal.spotbugs.SpotBugsResult; -import com.github.spotbugs.internal.spotbugs.SpotBugsSpec; -import com.github.spotbugs.internal.spotbugs.SpotBugsSpecBuilder; -import com.github.spotbugs.internal.spotbugs.SpotBugsWorkerManager; - -import edu.umd.cs.findbugs.annotations.NonNull; -import groovy.lang.Closure; - -/** - * Analyzes code with SpotBugs. See the - * SpotBugs Manual for additional - * information on configuration options. - */ -@CacheableTask -public class SpotBugsTask extends SourceTask implements VerificationTask, Reporting { - private FileCollection classes; - - private FileCollection classpath; - - private Set sourceDirs; - - private FileCollection spotbugsClasspath; - - private FileCollection pluginClasspath; - - private boolean ignoreFailures; - - private boolean showProgress; - - private String effort; - - private String reportLevel; - - private String maxHeapSize; - - private Collection visitors = new ArrayList<>(); - - private Collection omitVisitors = new ArrayList<>(); - - private TextResource includeFilterConfig; - - private TextResource excludeFilterConfig; - - private TextResource excludeBugsFilterConfig; - - private Collection extraArgs = new ArrayList<>(); - - private Collection jvmArgs = new ArrayList<>(); - - private String release; - - private String projectName; - - private SourceSet sourceSet; - - @Nested - private final SpotBugsReportsInternal reports; - - public SpotBugsTask() { - reports = getInstantiator().newInstance(SpotBugsReportsImpl.class, this); - } - - @Inject - public Instantiator getInstantiator() { - throw new UnsupportedOperationException(); - } - - @Inject - public WorkerProcessFactory getWorkerProcessBuilderFactory() { - throw new UnsupportedOperationException(); - } - - /** - *

Compatibility layer for API-safe call to {@link org.gradle.api.reporting.ReportContainer#getEnabledReports()}, - * introduced in Gradle 4.7 - * - *

This method assists the workaround for https://github.com/spotbugs/spotbugs-gradle-plugin/issues/61 - * - * @return true if any reports are enabled, otherwise logs a warning and returns false - */ - private boolean hasEnabledReports() { - boolean hasEnabledReports = !reports.getEnabledReports().isEmpty(); - - if (!hasEnabledReports) { - getProject().getLogger().lifecycle("WARNING: No SpotBugs report(s) were configured; aborting execution of {}", getPath()); - } - return hasEnabledReports; - } - - /** - * The reports to be generated by this task. - * - * @return The reports container - */ - @Override - public SpotBugsReports getReports() { - return reports; - } - - /** - * Configures the reports to be generated by this task. - * - * The contained reports can be configured by name and closures. Example: - * - *

-     * spotbugsTask {
-     *   reports {
-     *     xml {
-     *       destination "build/spotbugs.xml"
-     *     }
-     *   }
-     * }
-     * 
- * - * @param closure The configuration - * @return The reports container - */ - @Override - public SpotBugsReports reports(Closure closure) { - return reports(ConfigureUtil.configureUsing(closure)); - } - - /** - * Configures the reports to be generated by this task. - * - * The contained reports can be configured by name and closures. Example: - * - *
-     * spotbugsTask {
-     *   reports {
-     *     xml {
-     *       destination "build/spotbugs.xml"
-     *     }
-     *   }
-     * }
-     * 
- * - * - * @param configureAction The configuration - * @return The reports container - */ - @Override - public SpotBugsReports reports(Action configureAction) { - configureAction.execute(reports); - verify(reports); - return reports; - } - - private void verify(SpotBugsReportsInternal reports) { - if (reports.getText() != null && reports.getText().getDestination() == null) { - throw new InvalidUserDataException("No destination found for TEXT report. Set reports.text.destination to this task."); - } - if (reports.getXml() != null && reports.getXml().getDestination() == null) { - throw new InvalidUserDataException("No destination found for XML report. Set reports.xml.destination to this task."); - } - if (reports.getHtml() != null && reports.getHtml().getDestination() == null) { - throw new InvalidUserDataException("No destination found for HTML report. Set reports.html.destination to this task."); - } - if (reports.getEmacs() != null && reports.getEmacs().getDestination() == null) { - throw new InvalidUserDataException("No destination found for EMACS report. Set reports.emacs.destination to this task."); - } - } - - /** - * The filename of a filter specifying which bugs are reported. - * - * @return filename of a filter specifying which bugs are reported - */ - @Internal - public File getIncludeFilter() { - TextResource config = getIncludeFilterConfig(); - return config == null ? null : config.asFile(); - } - - /** - * The filename of a filter specifying which bugs are reported. - * - * @param filter - * filename of a filter specifying which bugs are report - */ - public void setIncludeFilter(File filter) { - setIncludeFilterConfig(getProject().getResources().getText().fromFile(filter)); - } - - /** - * The filename of a filter specifying bugs to exclude from being reported. - * - * @return filename of a filter specifying bugs to exclude from being reported - */ - @Internal - public File getExcludeFilter() { - TextResource config = getExcludeFilterConfig(); - return config == null ? null : config.asFile(); - } - - /** - * The filename of a filter specifying bugs to exclude from being reported. - * - * @param filter - * filename of a filter specifying bugs to exclude from being reported - */ - public void setExcludeFilter(File filter) { - setExcludeFilterConfig(getProject().getResources().getText().fromFile(filter)); - } - - /** - * The filename of a filter specifying baseline bugs to exclude from being reported. - * - * @return filename of a filter specifying baseline bugs to exclude from being reported - */ - @Internal - public File getExcludeBugsFilter() { - TextResource config = getExcludeBugsFilterConfig(); - return config == null ? null : config.asFile(); - } - - /** - * The filename of a filter specifying baseline bugs to exclude from being reported. - * - * @param filter - * filename of a filter specifying baseline bugs to exclude from being reported - */ - public void setExcludeBugsFilter(File filter) { - setExcludeBugsFilterConfig(getProject().getResources().getText().fromFile(filter)); - } - - @TaskAction - public void run() throws IOException, InterruptedException { - new SpotBugsClasspathValidator(JavaVersion.current()).validateClasspath( - getSpotbugsClasspath().getFiles().stream().map(File::getName).collect(Collectors.toSet())); - SpotBugsSpec spec = generateSpec(); - SpotBugsWorkerManager manager = new SpotBugsWorkerManager(); - - getLogging().captureStandardOutput(LogLevel.DEBUG); - getLogging().captureStandardError(LogLevel.DEBUG); - - //workaround for https://github.com/spotbugs/spotbugs-gradle-plugin/issues/61 - if(!hasEnabledReports()) { - return; - } - - SpotBugsResult result = manager.runWorker(getProject().getProjectDir(), getWorkerProcessBuilderFactory(), getSpotbugsClasspath(), spec); - evaluateResult(result); - } - - SpotBugsSpec generateSpec() { - SpotBugsSpecBuilder specBuilder = new SpotBugsSpecBuilder(getClasses()) - .withPluginsList(getPluginClasspath()) - .withSources(getAllSource()) - .withClasspath(getClasspath()) - .withShowProgress(getShowProgress()) - .withDebugging(getLogger().isDebugEnabled()) - .withEffort(getEffort()) - .withReportLevel(getReportLevel()) - .withMaxHeapSize(getMaxHeapSize()) - .withVisitors(getVisitors()) - .withOmitVisitors(getOmitVisitors()) - .withExcludeFilter(getExcludeFilter()) - .withIncludeFilter(getIncludeFilter()) - .withExcludeBugsFilter(getExcludeBugsFilter()) - .withRelease(getRelease()) - .withProjectName(getProjectName()) - .withExtraArgs(getExtraArgs()) - .withJvmArgs(getJvmArgs()) - .configureReports(getReports()); - - return specBuilder.build(); - } - - void evaluateResult(SpotBugsResult result) { - if (result.getException() != null) { - throw new GradleException("SpotBugs encountered an error. Run with --debug to get more information.", result.getException()); - } - - if (result.getErrorCount() > 0) { - throw new GradleException("SpotBugs encountered an error. Run with --debug to get more information."); - } - - if (result.getBugCount() > 0) { - String message = "Verification failed: SpotBugs rule violations were found."; - SingleFileReport report = reports.getFirstEnabled(); - if (report != null) { - String reportUrl = new ConsoleRenderer().asClickableFileUrl(report.getDestination()); - message += " See the report at: " + reportUrl; - } - - if (getIgnoreFailures()) { - getLogger().warn(message); - } else { - throw new GradleException(message); - } - - } - - } - - public SpotBugsTask extraArgs(Iterable arguments) { - for (String argument : arguments) { - extraArgs.add(argument); - } - - return this; - } - - public SpotBugsTask extraArgs(String... arguments) { - extraArgs.addAll(Arrays.asList(arguments)); - return this; - } - - public SpotBugsTask jvmArgs(Iterable arguments) { - for (String argument : arguments) { - jvmArgs.add(argument); - } - - return this; - } - - public SpotBugsTask jvmArgs(String... arguments) { - jvmArgs.addAll(Arrays.asList(arguments)); - return this; - } - - SpotBugsTask setSourceSet(SourceSet sourceSet) { - this.sourceDirs = sourceSet.getAllJava().getSrcDirs(); - this.sourceSet = sourceSet; - setSource(sourceDirs); - return this; - } - - /** - * {@inheritDoc} - */ - @Override - @PathSensitive(PathSensitivity.RELATIVE) - public FileTree getSource() { - return super.getSource(); - } - - @InputFiles - @PathSensitive(PathSensitivity.RELATIVE) - FileCollection getAllSource() { - return getProject().files(sourceDirs).plus(getSource()); - } - - /** - * The classes to be analyzed. - * - * @return classes to be analyzed - */ - @SkipWhenEmpty - @PathSensitive(PathSensitivity.RELATIVE) - @InputFiles - public FileCollection getClasses() { - return classes; - } - - /** - * @param classes - * classes to be analyzed - */ - public void setClasses(FileCollection classes) { - this.classes = classes; - } - - /** - * Compile class path for the classes to be analyzed. The classes on this class path are used during analysis but - * aren't analyzed themselves. - * - * @return compile class path for the classes to be analyze - */ - @Classpath - public FileCollection getClasspath() { - return classpath; - } - - /** - * @param classpath - * compile class path for the classes to be analyze - */ - public void setClasspath(FileCollection classpath) { - this.classpath = classpath; - } - - /** - * Class path holding the SpotBugs library. - * - * @return class path holding the SpotBugs library - */ - @Classpath - public FileCollection getSpotbugsClasspath() { - return spotbugsClasspath; - } - - /** - * @param spotbugsClasspath - * class path holding the SpotBugs library - */ - public void setSpotbugsClasspath(FileCollection spotbugsClasspath) { - this.spotbugsClasspath = spotbugsClasspath; - } - - /** - * Class path holding any additional SpotBugs plugins. - * - * @return class path holding any additional SpotBugs plugin - */ - @Classpath - public FileCollection getPluginClasspath() { - return pluginClasspath; - } - - /** - * @param pluginClasspath - * class path holding any additional SpotBugs plugin - */ - public void setPluginClasspath(FileCollection pluginClasspath) { - this.pluginClasspath = pluginClasspath; - } - - /** - * Whether or not to allow the build to continue if there are warnings. - */ - @Input - @Override - public boolean getIgnoreFailures() { - return ignoreFailures; - } - - @Override - public void setIgnoreFailures(boolean ignoreFailures) { - this.ignoreFailures = ignoreFailures; - } - - /** - * Indicates whether analysis progress should be rendered on standard output. Defaults to false. - * @return true iff progress report is enabled - */ - @Input - public boolean getShowProgress() { - return showProgress; - } - - public void setShowProgress(boolean showProgress) { - this.showProgress = showProgress; - } - - /** - * The analysis effort level. The value specified should be one of {@code min}, {@code default}, or {@code max}. - * Higher levels increase precision and find more bugs at the expense of running time and memory consumption. - * - * @return analysis effort level - */ - @Input - @Optional - public String getEffort() { - return effort; - } - - /** - * @param effort - * analysis effort level - */ - public void setEffort(String effort) { - this.effort = effort; - } - - /** - * The priority threshold for reporting bugs. If set to {@code low}, all bugs are reported. If set to {@code medium} - * (the default), medium and high priority bugs are reported. If set to {@code - * high}, only high priority bugs are reported. - * - * @return priority threshold for reporting bugs - */ - @Input - @Optional - public String getReportLevel() { - return reportLevel; - } - - /** - * @param reportLevel - * priority threshold for reporting bugs - */ - public void setReportLevel(String reportLevel) { - this.reportLevel = reportLevel; - } - - /** - * The maximum heap size for the forked spotbugs process (ex: '1g'). - * - * @return maximum heap size - */ - @Input - @Optional - public String getMaxHeapSize() { - return maxHeapSize; - } - - /** - * @param maxHeapSize - * maximum heap size - */ - public void setMaxHeapSize(String maxHeapSize) { - this.maxHeapSize = maxHeapSize; - } - - /** - * The bug detectors which should be run. The bug detectors are specified by their class names, without any package - * qualification. By default, all detectors which are not disabled by default are run. - * - * @return bug detectors which should be run - */ - @Input - @Optional - public Collection getVisitors() { - return visitors; - } - - /** - * @param visitors - * bug detectors which should be run - */ - public void setVisitors(Collection visitors) { - this.visitors = visitors; - } - - /** - * Similar to {@code visitors} except that it specifies bug detectors which should not be run. By default, no - * visitors are omitted. - * - * @return bug detectors which should not be run - */ - @Input - @Optional - public Collection getOmitVisitors() { - return omitVisitors; - } - - /** - * @param omitVisitors - * bug detectors which should not be run - */ - public void setOmitVisitors(Collection omitVisitors) { - this.omitVisitors = omitVisitors; - } - - /** - * A filter specifying which bugs are reported. Replaces the {@code includeFilter} property. - * - * @return filter specifying which bugs are reported - * - * @since 2.2 - */ - @Incubating - @Nested - @Optional - public TextResource getIncludeFilterConfig() { - return includeFilterConfig; - } - - /** - * @param includeFilterConfig - * filter specifying which bugs are reported - */ - public void setIncludeFilterConfig(TextResource includeFilterConfig) { - this.includeFilterConfig = includeFilterConfig; - } - - /** - * A filter specifying bugs to exclude from being reported. Replaces the {@code excludeFilter} property. - * - * @return filter specifying bugs to exclude from being reported - * - * @since 2.2 - */ - @Incubating - @Nested - @Optional - public TextResource getExcludeFilterConfig() { - return excludeFilterConfig; - } - - /** - * @param excludeFilterConfig - * filter specifying bugs to exclude from being reported - */ - public void setExcludeFilterConfig(TextResource excludeFilterConfig) { - this.excludeFilterConfig = excludeFilterConfig; - } - - /** - * A filter specifying baseline bugs to exclude from being reported. - * - * @return filter specifying baseline bugs to exclude from being reported - */ - @Incubating - @Nested - @Optional - public TextResource getExcludeBugsFilterConfig() { - return excludeBugsFilterConfig; - } - - /** - * @param excludeBugsFilterConfig - * filter specifying baseline bugs to exclude from being reported - */ - public void setExcludeBugsFilterConfig(TextResource excludeBugsFilterConfig) { - this.excludeBugsFilterConfig = excludeBugsFilterConfig; - } - - /** - * Any additional arguments (not covered here more explicitly like {@code effort}) to be passed along to SpotBugs. - *

- * Extra arguments are passed to SpotBugs after the arguments Gradle understands (like {@code effort} but before the - * list of classes to analyze. This should only be used for arguments that cannot be provided by Gradle directly. - * Gradle does not try to interpret or validate the arguments before passing them to SpotBugs. - *

- * See the SpotBugs - * TextUICommandLine source for available options. - * - * @return any additional arguments (not covered here more explicitly like {@code effort}) to be passed along to - * SpotBugs - * - * @since 2.6 - */ - @Input - @Optional - public Collection getExtraArgs() { - return extraArgs; - } - - /** - * @param extraArgs - * any additional arguments (not covered here more explicitly like {@code effort}) to be passed along to - * SpotBugs - */ - public void setExtraArgs(Collection extraArgs) { - this.extraArgs = extraArgs; - } - - @Input - @Optional - public Collection getJvmArgs() { - return jvmArgs; - } - - public void setJvmArgs(Collection jvmArgs) { - this.jvmArgs = jvmArgs; - } - - @Input - @Optional - @NonNull - public String getRelease() { - if (release != null) { - return release; - } - return String.valueOf(getProject().getVersion()); - } - - public void setRelease(String release) { - this.release = release; - } - - @Input - @Optional - @NonNull - public String getProjectName() { - if (projectName != null) { - return projectName; - } - if (sourceSet == null) { - return String.valueOf(getProject().getDisplayName()); - } else { - return String.format("%s (%s)", getProject().getDisplayName(), sourceSet.getName()); - } - } - - public void setProjectName(String projectName) { - this.projectName = projectName; - } -} diff --git a/src/main/java/com/github/spotbugs/SpotBugsXmlReport.java b/src/main/java/com/github/spotbugs/SpotBugsXmlReport.java deleted file mode 100644 index a8092a42..00000000 --- a/src/main/java/com/github/spotbugs/SpotBugsXmlReport.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.github.spotbugs; - -import org.gradle.api.Incubating; -import org.gradle.api.reporting.SingleFileReport; -import org.gradle.api.tasks.Internal; - -/** - * The single file XML report for SpotBugs. - */ -@Incubating -public interface SpotBugsXmlReport extends SingleFileReport { - /** - * Whether or not SpotBugs should generate XML augmented with human-readable messages. - * You should use this format if you plan to generate a report using an XSL stylesheet. - *

- * If {@code true}, SpotBugs will augment the XML with human-readable messages. - * If {@code false}, SpotBugs will not augment the XML with human-readable messages. - * - * @return Whether or not SpotBugs should generate XML augmented with human-readable messages. - */ - @Internal - boolean isWithMessages(); - - /** - * Whether or not SpotBugs should generate XML augmented with human-readable messages. - * - * @see #isWithMessages() - * @param withMessages Whether or not SpotBugs should generate XML augmented with human-readable messages. - */ - void setWithMessages(boolean withMessages); - -} \ No newline at end of file diff --git a/src/main/java/com/github/spotbugs/internal/SpotBugsHtmlReportImpl.java b/src/main/java/com/github/spotbugs/internal/SpotBugsHtmlReportImpl.java deleted file mode 100644 index 0063244e..00000000 --- a/src/main/java/com/github/spotbugs/internal/SpotBugsHtmlReportImpl.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.github.spotbugs.internal; - -import java.io.File; -import java.util.Optional; - -import org.gradle.api.InvalidUserDataException; -import org.gradle.api.Task; -import org.gradle.api.artifacts.Configuration; -import org.gradle.api.artifacts.Dependency; -import org.gradle.api.logging.Logger; -import org.gradle.api.reporting.internal.CustomizableHtmlReportImpl; -import org.gradle.api.resources.ResourceHandler; -import org.gradle.api.resources.TextResource; -import org.gradle.api.resources.TextResourceFactory; -import org.gradle.api.tasks.Nested; - -public abstract class SpotBugsHtmlReportImpl extends CustomizableHtmlReportImpl { - private static final long serialVersionUID = 6474874842199703745L; - private final transient ResourceHandler handler; - private final transient Configuration configuration; - private final transient Logger logger; - - /** - * Null-able string representing relative file path of XSL packaged in spotbugs.jar. - */ - private String stylesheet; - - public SpotBugsHtmlReportImpl(String name, Task task) { - super(name, task); - handler = task.getProject().getResources(); - configuration = task.getProject().getConfigurations().getAt("spotbugs"); - logger = task.getLogger(); - } - - public void setStylesheet(String fileName) { - this.stylesheet = fileName; - } - - @Nested - @Override - public TextResource getStylesheet() { - if (stylesheet == null) { - return super.getStylesheet(); - } - - TextResourceFactory factory = handler.getText(); - Optional spotbugs = configuration.files(this::find).stream().findFirst(); - if (spotbugs.isPresent()) { - File jar = spotbugs.get(); - logger.debug("Specified stylesheet ({}) found in spotbugs configuration: {}", stylesheet, jar.getAbsolutePath()); - return factory.fromArchiveEntry(jar, stylesheet); - } else { - throw new InvalidUserDataException("Specified stylesheet (" + stylesheet + ") was not found in spotbugs configuration"); - } - } - - private boolean find(Dependency d) { - return "com.github.spotbugs".equals(d.getGroup()) && "spotbugs".equals(d.getName()); - } -} diff --git a/src/main/java/com/github/spotbugs/internal/SpotBugsReportsImpl.java b/src/main/java/com/github/spotbugs/internal/SpotBugsReportsImpl.java deleted file mode 100644 index 94b04237..00000000 --- a/src/main/java/com/github/spotbugs/internal/SpotBugsReportsImpl.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.github.spotbugs.internal; - -import org.gradle.api.Task; -import org.gradle.api.internal.CollectionCallbackActionDecorator; -import org.gradle.api.reporting.SingleFileReport; -import org.gradle.api.reporting.internal.TaskGeneratedSingleFileReport; -import org.gradle.api.reporting.internal.TaskReportContainer; - -import com.github.spotbugs.SpotBugsXmlReport; -import com.github.spotbugs.internal.spotbugs.SpotBugsXmlReportImpl; - -public class SpotBugsReportsImpl extends TaskReportContainer implements SpotBugsReportsInternal { - -public SpotBugsReportsImpl(Task task) { - super(SingleFileReport.class, task, CollectionCallbackActionDecorator.NOOP); - - add(SpotBugsXmlReportImpl.class, "xml", task); - add(SpotBugsHtmlReportImpl.class, "html", task); - add(TaskGeneratedSingleFileReport.class, "text", task); - add(TaskGeneratedSingleFileReport.class, "emacs", task); - } - - @Override -public SpotBugsXmlReport getXml() { - return (SpotBugsXmlReport) getByName("xml"); - } - - @Override -public SingleFileReport getHtml() { - return getByName("html"); - } - - @Override -public SingleFileReport getText() { - return getByName("text"); - } - - @Override -public SingleFileReport getEmacs() { - return getByName("emacs"); - } - - @Override - public Boolean getWithMessagesFlag() { - SpotBugsXmlReport report = (SpotBugsXmlReport)getEnabled().findByName("xml"); - return report != null ? report.isWithMessages() : Boolean.FALSE; - } -} diff --git a/src/main/java/com/github/spotbugs/internal/SpotBugsReportsInternal.java b/src/main/java/com/github/spotbugs/internal/SpotBugsReportsInternal.java deleted file mode 100644 index 0b3f0aeb..00000000 --- a/src/main/java/com/github/spotbugs/internal/SpotBugsReportsInternal.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.github.spotbugs.internal; - -import org.gradle.api.reporting.SingleFileReport; -import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.Internal; -import org.gradle.api.tasks.Optional; - -import com.github.spotbugs.SpotBugsReports; - -public interface SpotBugsReportsInternal extends SpotBugsReports { - @Internal - SingleFileReport getFirstEnabled(); - - @Input - @Optional - Boolean getWithMessagesFlag(); -} \ No newline at end of file diff --git a/src/main/java/com/github/spotbugs/internal/spotbugs/SpotBugsClasspathValidator.java b/src/main/java/com/github/spotbugs/internal/spotbugs/SpotBugsClasspathValidator.java deleted file mode 100644 index b992ce80..00000000 --- a/src/main/java/com/github/spotbugs/internal/spotbugs/SpotBugsClasspathValidator.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.github.spotbugs.internal.spotbugs; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.gradle.api.GradleException; -import org.gradle.api.JavaVersion; -import org.gradle.util.VersionNumber; - -public class SpotBugsClasspathValidator { - - private final JavaVersion javaVersion; - - public SpotBugsClasspathValidator(JavaVersion javaVersion) { - this.javaVersion = javaVersion; - } - - public void validateClasspath(Iterable fileNamesOnClasspath) { - VersionNumber v = getSpotbugsVersion(fileNamesOnClasspath); - boolean java8orMore = javaVersion.compareTo(JavaVersion.VERSION_1_7) > 0; - boolean spotbugs2orLess = v.getMajor() < 3; - if (java8orMore && spotbugs2orLess) { - throw new SpotBugsVersionTooLowException("The version of SpotBugs (" + v + ") inferred from SpotBugs classpath is too low to work with currently used Java version (" + javaVersion + ")." - + " Please use higher version of SpotBugs. Inspected SpotBugs classpath: " + fileNamesOnClasspath); - } - } - - static class SpotBugsVersionTooLowException extends GradleException { - private static final long serialVersionUID = 1L; - - SpotBugsVersionTooLowException(String message) { - super(message); - } - } - - private VersionNumber getSpotbugsVersion(Iterable classpath) { - for (String f: classpath) { - Matcher m = Pattern.compile("spotbugs-(\\d+\\.\\d+\\.\\d+).*\\.jar").matcher(f); - if (m.matches()) { - return VersionNumber.parse(m.group(1)); - } - } - throw new GradleException("Unable to infer the version of SpotBugs from currently specified SpotBugs classpath: " + classpath); - } -} diff --git a/src/main/java/com/github/spotbugs/internal/spotbugs/SpotBugsExecutor.java b/src/main/java/com/github/spotbugs/internal/spotbugs/SpotBugsExecutor.java deleted file mode 100644 index 44487b21..00000000 --- a/src/main/java/com/github/spotbugs/internal/spotbugs/SpotBugsExecutor.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.github.spotbugs.internal.spotbugs; - -import java.io.IOException; -import java.util.List; - -import edu.umd.cs.findbugs.FindBugs; -import edu.umd.cs.findbugs.FindBugs2; -import edu.umd.cs.findbugs.IFindBugsEngine; -import edu.umd.cs.findbugs.TextUICommandLine; - -public class SpotBugsExecutor implements SpotBugsWorker { - @Override - public SpotBugsResult runSpotbugs(SpotBugsSpec spec) throws IOException, InterruptedException { - final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); - try { - final List args = spec.getArguments(); - String[] strArray = args.toArray(new String[0]); - - Thread.currentThread().setContextClassLoader(FindBugs2.class.getClassLoader()); - FindBugs2 findBugs2 = new FindBugs2(); - TextUICommandLine commandLine = new TextUICommandLine(); - FindBugs.processCommandLine(commandLine, strArray, findBugs2); - findBugs2.execute(); - - return createSpotbugsResult(findBugs2); - } finally { - Thread.currentThread().setContextClassLoader(contextClassLoader); - } - } - - SpotBugsResult createSpotbugsResult(IFindBugsEngine findBugs) { - int bugCount = findBugs.getBugCount(); - int missingClassCount = findBugs.getMissingClassCount(); - int errorCount = findBugs.getErrorCount(); - return new SpotBugsResult(bugCount, missingClassCount, errorCount); - } -} \ No newline at end of file diff --git a/src/main/java/com/github/spotbugs/internal/spotbugs/SpotBugsResult.java b/src/main/java/com/github/spotbugs/internal/spotbugs/SpotBugsResult.java deleted file mode 100644 index 4703fc73..00000000 --- a/src/main/java/com/github/spotbugs/internal/spotbugs/SpotBugsResult.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.github.spotbugs.internal.spotbugs; - -import java.io.Serializable; - -public class SpotBugsResult implements Serializable { - private static final long serialVersionUID = 1L; - private final int bugCount; - private final int missingClassCount; - private final int errorCount; - private final Throwable exception; - - public SpotBugsResult(int bugCount, int missingClassCount, int errorCount) { - this(bugCount, missingClassCount, errorCount, null); - } - - public SpotBugsResult(int bugCount, int missingClassCount, int errorCount, Throwable exception) { - this.bugCount = bugCount; - this.missingClassCount = missingClassCount; - this.errorCount = errorCount; - this.exception = exception; - } - - public int getBugCount() { - return bugCount; - } - - public int getMissingClassCount() { - return missingClassCount; - } - - public int getErrorCount() { - return errorCount; - } - - public Throwable getException() { - return exception; - } -} \ No newline at end of file diff --git a/src/main/java/com/github/spotbugs/internal/spotbugs/SpotBugsSpec.java b/src/main/java/com/github/spotbugs/internal/spotbugs/SpotBugsSpec.java deleted file mode 100644 index 51a51c50..00000000 --- a/src/main/java/com/github/spotbugs/internal/spotbugs/SpotBugsSpec.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.github.spotbugs.internal.spotbugs; - -import org.apache.commons.lang.builder.ToStringBuilder; - -import java.io.Serializable; -import java.util.Collection; -import java.util.List; - -public class SpotBugsSpec implements Serializable { - private static final long serialVersionUID = 1L; - private List arguments; - private String maxHeapSize; - private boolean debugEnabled; - private Collection jvmArgs; - - public SpotBugsSpec(List arguments, String maxHeapSize, boolean debugEnabled, Collection jvmArgs) { - this.debugEnabled = debugEnabled; - this.maxHeapSize = maxHeapSize; - this.arguments = arguments; - this.jvmArgs = jvmArgs; - } - - public List getArguments() { - return arguments; - } - - public String getMaxHeapSize() { - return maxHeapSize; - } - - public boolean isDebugEnabled() { - return debugEnabled; - } - - public Collection getJvmArgs() { - return jvmArgs; - } - - @Override -public String toString() { - return new ToStringBuilder(this).append("arguments", arguments).append("debugEnabled", debugEnabled).toString(); - } -} \ No newline at end of file diff --git a/src/main/java/com/github/spotbugs/internal/spotbugs/SpotBugsSpecBuilder.java b/src/main/java/com/github/spotbugs/internal/spotbugs/SpotBugsSpecBuilder.java deleted file mode 100644 index f4e12c26..00000000 --- a/src/main/java/com/github/spotbugs/internal/spotbugs/SpotBugsSpecBuilder.java +++ /dev/null @@ -1,291 +0,0 @@ -package com.github.spotbugs.internal.spotbugs; - -import java.io.File; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Set; -import java.util.stream.Collectors; - -import org.gradle.api.InvalidUserDataException; -import org.gradle.api.file.FileCollection; -import org.gradle.api.reporting.internal.CustomizableHtmlReportImpl; -import org.gradle.util.CollectionUtils; - -import com.github.spotbugs.SpotBugsReports; -import com.github.spotbugs.internal.SpotBugsReportsImpl; - -import edu.umd.cs.findbugs.annotations.Nullable; - -public class SpotBugsSpecBuilder { - private static final Set VALID_EFFORTS = createImmutableSet("min", "default", "max"); - private static final Set VALID_REPORT_LEVELS = createImmutableSet("experimental", "low", "medium", "high"); - - private FileCollection pluginsList; - private FileCollection sources; - private FileCollection classpath; - private FileCollection classes; - private SpotBugsReports reports; - - private String effort; - private String reportLevel; - private String maxHeapSize; - private Collection visitors; - private Collection omitVisitors; - private File excludeFilter; - private File includeFilter; - private File excludeBugsFilter; - private Collection extraArgs; - private Collection jvmArgs; - private boolean showProgress; - private boolean debugEnabled; - private String release; - private String projectName; - - public SpotBugsSpecBuilder(FileCollection classes) { - if (classes == null || classes.isEmpty()) { - throw new InvalidUserDataException("No classes configured for SpotBugs analysis."); - } - this.classes = classes; - } - - public SpotBugsSpecBuilder withPluginsList(FileCollection pluginsClasspath) { - this.pluginsList = pluginsClasspath; - return this; - } - - public SpotBugsSpecBuilder withSources(FileCollection sources) { - this.sources = sources; - return this; - } - - public SpotBugsSpecBuilder withClasspath(FileCollection classpath) { - this.classpath = classpath; - return this; - } - - public SpotBugsSpecBuilder configureReports(SpotBugsReports reports) { - this.reports = reports; - return this; - } - - - public SpotBugsSpecBuilder withEffort(String effort) { - if (effort != null && !VALID_EFFORTS.contains(effort)) { - throw new InvalidUserDataException("Invalid value for SpotBugs 'effort' property: " + effort); - } - this.effort = effort; - return this; - } - - public SpotBugsSpecBuilder withReportLevel(String reportLevel) { - if (reportLevel != null && !VALID_REPORT_LEVELS.contains(reportLevel)) { - throw new InvalidUserDataException("Invalid value for SpotBugs 'reportLevel' property: " + reportLevel); - } - this.reportLevel = reportLevel; - return this; - } - - public SpotBugsSpecBuilder withMaxHeapSize(String maxHeapSize) { - this.maxHeapSize = maxHeapSize; - return this; - } - - public SpotBugsSpecBuilder withVisitors(Collection visitors) { - this.visitors = visitors; - return this; - } - - public SpotBugsSpecBuilder withOmitVisitors(Collection omitVisitors) { - this.omitVisitors = omitVisitors; - return this; - } - - public SpotBugsSpecBuilder withExcludeFilter(File excludeFilter) { - if (excludeFilter != null && !excludeFilter.canRead()) { - String errorStr = String.format("Cannot read file specified for SpotBugs 'excludeFilter' property: %s", excludeFilter); - throw new InvalidUserDataException(errorStr); - } - - this.excludeFilter = excludeFilter; - return this; - } - - public SpotBugsSpecBuilder withIncludeFilter(File includeFilter) { - if (includeFilter != null && !includeFilter.canRead()) { - String errorStr = String.format("Cannot read file specified for SpotBugs 'includeFilter' property: %s", includeFilter); - throw new InvalidUserDataException(errorStr); - } - - this.includeFilter = includeFilter; - return this; - } - - public SpotBugsSpecBuilder withExcludeBugsFilter(File excludeBugsFilter) { - if (excludeBugsFilter != null && !excludeBugsFilter.canRead()) { - String errorStr = String.format("Cannot read file specified for SpotBugs 'excludeBugsFilter' property: %s", excludeBugsFilter); - throw new InvalidUserDataException(errorStr); - } - - this.excludeBugsFilter = excludeBugsFilter; - - return this; - } - - public SpotBugsSpecBuilder withExtraArgs(Collection extraArgs) { - this.extraArgs = extraArgs; - return this; - } - - public SpotBugsSpecBuilder withShowProgress(boolean showProgress) { - this.showProgress = showProgress; - return this; - } - - public SpotBugsSpecBuilder withDebugging(boolean debugEnabled) { - this.debugEnabled = debugEnabled; - return this; - } - - public SpotBugsSpecBuilder withJvmArgs(@Nullable Collection jvmArgs) { - this.jvmArgs = jvmArgs; - return this; - } - - public SpotBugsSpecBuilder withRelease(@Nullable String release) { - this.release = release; - return this; - } - - public SpotBugsSpecBuilder withProjectName(@Nullable String projectName) { - this.projectName = projectName; - return this; - } - - public SpotBugsSpec build() { - ArrayList args = new ArrayList<>(); - args.add("-pluginList"); - args.add(pluginsList == null ? "" : pluginsList.getAsPath()); - args.add("-sortByClass"); - args.add("-timestampNow"); - - if (showProgress) { - args.add("-progress"); - } - - if (reports != null && !reports.getEnabled().isEmpty()) { - if (reports.getEnabled().size() == 1) { - SpotBugsReportsImpl reportsImpl = (SpotBugsReportsImpl) reports; - String outputArg = "-" + reportsImpl.getFirstEnabled().getName(); - if (reportsImpl.getFirstEnabled() instanceof SpotBugsXmlReportImpl) { - SpotBugsXmlReportImpl r = (SpotBugsXmlReportImpl) reportsImpl.getFirstEnabled(); - if (r.isWithMessages()) { - outputArg += ":withMessages"; - } - } else if (reportsImpl.getFirstEnabled() instanceof CustomizableHtmlReportImpl) { - CustomizableHtmlReportImpl r = (CustomizableHtmlReportImpl) reportsImpl.getFirstEnabled(); - if (r.getStylesheet() != null) { - outputArg += ':' + r.getStylesheet().asFile().getAbsolutePath(); - } - } - if ("-text".equals(outputArg)) { - // text mode is default behaviour of SpotBugs, then no need to add argument - } else { - args.add(outputArg); - } - args.add("-outputFile"); - args.add(reportsImpl.getFirstEnabled().getDestination().getAbsolutePath()); - } else { - throw new InvalidUserDataException("SpotBugs tasks can only have one report enabled, however more than one report was enabled. You need to disable all but one of them."); - } - } - - if (has(sources)) { - args.add("-sourcepath"); - args.add(sources.getAsPath()); - } - - if (has(classpath)) { - args.add("-auxclasspath"); - - // Filter unexisting files as SpotBugs can't handle them. - args.add(classpath.filter(File::exists).getAsPath()); - } - - if (has(effort)) { - args.add(String.format("-effort:%s", effort)); - } - - if (has(reportLevel)) { - args.add(String.format("-%s", reportLevel)); - } - - if (has(visitors)) { - args.add("-visitors"); - args.add(CollectionUtils.join(",", visitors)); - } - - if (has(omitVisitors)) { - args.add("-omitVisitors"); - args.add(CollectionUtils.join(",", omitVisitors)); - } - - if (has(excludeFilter)) { - args.add("-exclude"); - args.add(excludeFilter.getPath()); - } - - if (has(includeFilter)) { - args.add("-include"); - args.add(includeFilter.getPath()); - } - - if (has(excludeBugsFilter)) { - args.add("-excludeBugs"); - args.add(excludeBugsFilter.getPath()); - } - - if (has(release)) { - args.add("-release"); - args.add(release); - } - - if (has(projectName)) { - args.add("-projectName"); - args.add(projectName); - } - - if (has(extraArgs)) { - args.addAll(extraArgs); - } - - for (File classFile : classes.getFiles()) { - args.add(classFile.getAbsolutePath()); - } - - return new SpotBugsSpec(args, maxHeapSize, debugEnabled, - (this.jvmArgs == null ? Collections.emptyList() : this.jvmArgs)); - } - - private boolean has(String str) { - return str != null && str.length() > 0; - } - - private boolean has(File file) { - return file != null && file.canRead(); - } - - private boolean has(Collection collection) { - return collection != null && !collection.isEmpty(); - } - - private boolean has(FileCollection fileCollection) { - return fileCollection != null && !fileCollection.isEmpty(); - } - - private static final Set createImmutableSet(String... strings) { - Set set = Arrays.asList(strings).stream().collect(Collectors.toSet()); - return Collections.unmodifiableSet(set); - } -} diff --git a/src/main/java/com/github/spotbugs/internal/spotbugs/SpotBugsWorker.java b/src/main/java/com/github/spotbugs/internal/spotbugs/SpotBugsWorker.java deleted file mode 100644 index 52d6c503..00000000 --- a/src/main/java/com/github/spotbugs/internal/spotbugs/SpotBugsWorker.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.github.spotbugs.internal.spotbugs; - -import java.io.IOException; - -public interface SpotBugsWorker { - SpotBugsResult runSpotbugs(SpotBugsSpec spec) throws IOException, InterruptedException; -} \ No newline at end of file diff --git a/src/main/java/com/github/spotbugs/internal/spotbugs/SpotBugsWorkerManager.java b/src/main/java/com/github/spotbugs/internal/spotbugs/SpotBugsWorkerManager.java deleted file mode 100644 index e13675ca..00000000 --- a/src/main/java/com/github/spotbugs/internal/spotbugs/SpotBugsWorkerManager.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.github.spotbugs.internal.spotbugs; - -import java.io.File; -import java.io.IOException; -import java.util.Arrays; - -import org.gradle.api.file.FileCollection; -import org.gradle.process.internal.JavaExecHandleBuilder; -import org.gradle.process.internal.worker.SingleRequestWorkerProcessBuilder; -import org.gradle.process.internal.worker.WorkerProcessFactory; - -public class SpotBugsWorkerManager { - public SpotBugsResult runWorker(File workingDir, WorkerProcessFactory workerFactory, FileCollection findBugsClasspath, SpotBugsSpec spec) throws IOException, InterruptedException { - SpotBugsWorker worker = createWorkerProcess(workingDir, workerFactory, findBugsClasspath, spec); - return worker.runSpotbugs(spec); - } - - private SpotBugsWorker createWorkerProcess(File workingDir, WorkerProcessFactory workerFactory, FileCollection findBugsClasspath, SpotBugsSpec spec) { - SingleRequestWorkerProcessBuilder builder = workerFactory.singleRequestWorker(SpotBugsWorker.class, SpotBugsExecutor.class); - builder.setBaseName("Gradle SpotBugs Worker"); - builder.applicationClasspath(findBugsClasspath); - builder.sharedPackages(Arrays.asList("edu.umd.cs.findbugs")); - JavaExecHandleBuilder javaCommand = builder.getJavaCommand(); - javaCommand.setWorkingDir(workingDir); - javaCommand.setMaxHeapSize(spec.getMaxHeapSize()); - javaCommand.jvmArgs(spec.getJvmArgs()); - return builder.build(); - } -} \ No newline at end of file diff --git a/src/main/java/com/github/spotbugs/internal/spotbugs/SpotBugsXmlReportImpl.java b/src/main/java/com/github/spotbugs/internal/spotbugs/SpotBugsXmlReportImpl.java deleted file mode 100644 index d094f4c3..00000000 --- a/src/main/java/com/github/spotbugs/internal/spotbugs/SpotBugsXmlReportImpl.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.github.spotbugs.internal.spotbugs; - -import org.gradle.api.Task; -import org.gradle.api.reporting.internal.TaskGeneratedSingleFileReport; - -import com.github.spotbugs.SpotBugsXmlReport; - -public abstract class SpotBugsXmlReportImpl extends TaskGeneratedSingleFileReport implements SpotBugsXmlReport { - private static final long serialVersionUID = 1L; - private boolean withMessages; - - public SpotBugsXmlReportImpl(String name, Task task) { - super(name, task); - } - - @Override - public boolean isWithMessages() { - return withMessages; - } - - @Override - public void setWithMessages(boolean withMessages) { - this.withMessages = withMessages; - } - -} \ No newline at end of file diff --git a/src/main/resources/META-INF/gradle-plugins/com.github.spotbugs.properties b/src/main/resources/META-INF/gradle-plugins/com.github.spotbugs.properties deleted file mode 100644 index a8a4b8af..00000000 --- a/src/main/resources/META-INF/gradle-plugins/com.github.spotbugs.properties +++ /dev/null @@ -1 +0,0 @@ -implementation-class=com.github.spotbugs.SpotBugsPlugin \ No newline at end of file diff --git a/src/test/java/com/github/spotbugs/Bar.groovy b/src/test/java/com/github/spotbugs/Bar.groovy deleted file mode 100644 index 7d77d933..00000000 --- a/src/test/java/com/github/spotbugs/Bar.groovy +++ /dev/null @@ -1,11 +0,0 @@ -package com.github.spotbugs - -/** - * Simple test class. - * - * @author Kevin Mc Tiernan, 23.05.2018, kemc@skagenfondene.no / kevin.tiernan@knowit.no - */ -class Bar { - - private String UNUSED_VARIABLE = "UNUSED" -} diff --git a/src/test/java/com/github/spotbugs/Foo.java b/src/test/java/com/github/spotbugs/Foo.java deleted file mode 100644 index 8f4a433b..00000000 --- a/src/test/java/com/github/spotbugs/Foo.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.github.spotbugs; - -public class Foo { - - public static void main(String[] args) { - System.out.println("hello!"); - } - -} diff --git a/src/test/java/com/github/spotbugs/FooTest.groovy b/src/test/java/com/github/spotbugs/FooTest.groovy deleted file mode 100644 index 66555833..00000000 --- a/src/test/java/com/github/spotbugs/FooTest.groovy +++ /dev/null @@ -1,7 +0,0 @@ -package com.github.spotbugs - -/** - * @author Kevin Mc Tiernan, 23.05.2018, kemc@skagenfondene.no / kevin.tiernan@knowit.no - */ -class FooTest { -} diff --git a/src/test/java/com/github/spotbugs/HtmlReportTest.java b/src/test/java/com/github/spotbugs/HtmlReportTest.java deleted file mode 100644 index dd3d3583..00000000 --- a/src/test/java/com/github/spotbugs/HtmlReportTest.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.github.spotbugs; - -import static org.hamcrest.CoreMatchers.containsString; -import static org.junit.Assert.assertThat; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; -import java.util.Arrays; -import java.util.stream.Collectors; - -import org.gradle.testkit.runner.GradleRunner; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -public class HtmlReportTest { - @Rule - public TemporaryFolder folder = new TemporaryFolder(); - - @Before - public void createProject() throws IOException { - Files.copy(Paths.get("src/test/resources/HtmlReportTest.gradle"), folder.getRoot().toPath().resolve("build.gradle"), - StandardCopyOption.COPY_ATTRIBUTES); - - File sourceDir = folder.newFolder("src", "main", "java"); - File to = new File(sourceDir, "Foo.java"); - File from = new File("src/test/java/com/github/spotbugs/Foo.java"); - Files.copy(from.toPath(), to.toPath(), StandardCopyOption.COPY_ATTRIBUTES); - Files.write(folder.newFile("settings.gradle").toPath(), "rootProject.name = 'my project name'".getBytes()); - } - - @Test - public void testReportContainsVersion() throws Exception { - GradleRunner.create().withProjectDir(folder.getRoot()) - .withArguments(Arrays.asList("spotbugsMain")).withPluginClasspath().build(); - Path report = folder.getRoot().toPath().resolve("build").resolve("reports").resolve("spotbugs").resolve("main.html"); - String html = Files.readAllLines(report).stream().collect(Collectors.joining("\n")); - assertThat(html, containsString("\"1.2.3\"")); - } - - @Test - public void testReportContainsProjectName() throws Exception { - GradleRunner.create().withProjectDir(folder.getRoot()) - .withArguments(Arrays.asList("spotbugsMain")).withPluginClasspath().build(); - Path report = folder.getRoot().toPath().resolve("build").resolve("reports").resolve("spotbugs").resolve("main.html"); - String html = Files.readAllLines(report).stream().collect(Collectors.joining("\n")); - assertThat(html, containsString("'my project name' (main)")); - } - -} diff --git a/src/test/java/com/github/spotbugs/Issue31Test.java b/src/test/java/com/github/spotbugs/Issue31Test.java deleted file mode 100644 index b4015f50..00000000 --- a/src/test/java/com/github/spotbugs/Issue31Test.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Contributions to SpotBugs - * Copyright (C) 2018, Kengo TODA - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -package com.github.spotbugs; - - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; -import java.util.Arrays; - -import org.gradle.testkit.runner.BuildResult; -import org.gradle.testkit.runner.GradleRunner; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -/** - * @see GitHub issue - */ -public class Issue31Test { - @Rule - public TemporaryFolder folder = new TemporaryFolder(); - - @Before - public void createProject() throws IOException { - Files.copy(Paths.get("src/test/resources/Issue31.gradle"), folder.getRoot().toPath().resolve("build.gradle"), - StandardCopyOption.COPY_ATTRIBUTES); - - File sourceDir = folder.newFolder("src", "main", "java"); - File to = new File(sourceDir, "Foo.java"); - File from = new File("src/test/java/com/github/spotbugs/Foo.java"); - Files.copy(from.toPath(), to.toPath(), StandardCopyOption.COPY_ATTRIBUTES); - } - - @Test - public void test() throws Exception { - BuildResult result = GradleRunner.create().withProjectDir(folder.getRoot()) - .withArguments(Arrays.asList("spotbugsMain")).withPluginClasspath().build(); - } -} diff --git a/src/test/java/com/github/spotbugs/Issue423Test.java b/src/test/java/com/github/spotbugs/Issue423Test.java deleted file mode 100644 index 0a6044b4..00000000 --- a/src/test/java/com/github/spotbugs/Issue423Test.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Contributions to SpotBugs - * Copyright (C) 2017, kengo - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -package com.github.spotbugs; - -import static org.hamcrest.CoreMatchers.containsString; -import static org.junit.Assert.assertThat; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; -import java.util.Arrays; - -import org.gradle.testkit.runner.BuildResult; -import org.gradle.testkit.runner.GradleRunner; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -/** - * If reports.xml.destination is null, we should print user friendly error message - * @since 3.1.0 - */ -public class Issue423Test { - @Rule - public TemporaryFolder folder = new TemporaryFolder(); - - @Before - public void createProject() throws IOException { - Files.copy(Paths.get("src/test/resources/Issue423.gradle"), folder.getRoot().toPath().resolve("build.gradle"), - StandardCopyOption.COPY_ATTRIBUTES); - - File sourceDir = folder.newFolder("src", "main", "java"); - File to = new File(sourceDir, "Foo.java"); - File from = new File("src/test/java/com/github/spotbugs/Foo.java"); - Files.copy(from.toPath(), to.toPath(), StandardCopyOption.COPY_ATTRIBUTES); - } - - @Test - public void testSpotBugsTaskCanRun() throws Exception { - BuildResult result = GradleRunner.create().withProjectDir(folder.getRoot()) - .withArguments(Arrays.asList("classes", "spotbugs")).withPluginClasspath().buildAndFail(); - assertThat(result.getOutput(), - containsString( - "No destination found for XML report. Set reports.xml.destination to this task.")); - } -} diff --git a/src/test/java/com/github/spotbugs/Issue440Test.java b/src/test/java/com/github/spotbugs/Issue440Test.java deleted file mode 100644 index 828875ae..00000000 --- a/src/test/java/com/github/spotbugs/Issue440Test.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Contributions to SpotBugs - * Copyright (C) 2017, kengo - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -package com.github.spotbugs; - -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; -import java.util.Arrays; - -import org.gradle.testkit.runner.BuildResult; -import org.gradle.testkit.runner.GradleRunner; -import org.gradle.testkit.runner.TaskOutcome; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -public class Issue440Test { - @Rule - public TemporaryFolder folder = new TemporaryFolder(); - - @Before - public void createProject() throws IOException { - Files.copy(Paths.get("src/test/resources/Issue440.gradle"), folder.getRoot().toPath().resolve("build.gradle"), - StandardCopyOption.COPY_ATTRIBUTES); - - File sourceDir = folder.newFolder("src", "main", "java"); - File to = new File(sourceDir, "Foo.java"); - File from = new File("src/test/java/com/github/spotbugs/Foo.java"); - Files.copy(from.toPath(), to.toPath(), StandardCopyOption.COPY_ATTRIBUTES); - } - - @Test - public void testJavaCompilationRunsBeforeSpotBugsTask() throws Exception { - BuildResult result = GradleRunner.create().withProjectDir(folder.getRoot()) - .withArguments(Arrays.asList("spotbugsMain")).withPluginClasspath().build(); - assertThat(result.task(":compileJava").getOutcome(), is(TaskOutcome.SUCCESS)); - assertThat(result.task(":classes").getOutcome(), is(TaskOutcome.SUCCESS)); - } -} diff --git a/src/test/java/com/github/spotbugs/Issue54Test.java b/src/test/java/com/github/spotbugs/Issue54Test.java deleted file mode 100644 index cad19ba6..00000000 --- a/src/test/java/com/github/spotbugs/Issue54Test.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Contributions to SpotBugs - * Copyright (C) 2018, kengo - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -package com.github.spotbugs; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.core.StringContains.containsString; -import static org.junit.Assert.assertThat; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; -import java.util.Arrays; - -import org.gradle.testkit.runner.BuildResult; -import org.gradle.testkit.runner.GradleRunner; -import org.gradle.testkit.runner.TaskOutcome; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -/** - * @see GitHub issue - */ -public class Issue54Test { - @Rule - public TemporaryFolder folder = new TemporaryFolder(); - - @Before - public void createProject() throws IOException { - Files.copy(Paths.get("src/test/resources/Issue54.gradle"), folder.getRoot().toPath().resolve("build.gradle"), - StandardCopyOption.COPY_ATTRIBUTES); - - File sourceDir = folder.newFolder("src", "main", "java"); - File to = new File(sourceDir, "Foo.java"); - File from = new File("src/test/java/com/github/spotbugs/Foo.java"); - Files.copy(from.toPath(), to.toPath(), StandardCopyOption.COPY_ATTRIBUTES); - } - - @Test - public void test() throws Exception { - BuildResult result = GradleRunner.create().withProjectDir(folder.getRoot()) - .withArguments(Arrays.asList("spotbugsMain")).withPluginClasspath().buildAndFail(); - assertThat(result.task(":spotbugsMain").getOutcome(), is(TaskOutcome.FAILED)); - assertThat(result.getOutput(), containsString("No classes configured for SpotBugs analysis.")); - } -} diff --git a/src/test/java/com/github/spotbugs/KotlinBuildScriptTest.java b/src/test/java/com/github/spotbugs/KotlinBuildScriptTest.java deleted file mode 100644 index d742f1d2..00000000 --- a/src/test/java/com/github/spotbugs/KotlinBuildScriptTest.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.github.spotbugs; - -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; -import java.util.Arrays; -import java.util.Optional; - -import org.gradle.testkit.runner.BuildResult; -import org.gradle.testkit.runner.BuildTask; -import org.gradle.testkit.runner.GradleRunner; -import org.gradle.testkit.runner.TaskOutcome; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -public class KotlinBuildScriptTest { - - @Rule - public TemporaryFolder folder= new TemporaryFolder(); - - private File sourceDir; - - @Before - public void createKotlinDslProject() throws IOException { - Files.copy(Paths.get("src/test/resources/KotlinBuildScript.gradle.kts"), folder.getRoot().toPath().resolve("build.gradle.kts"), - StandardCopyOption.COPY_ATTRIBUTES); - - sourceDir = folder.newFolder("src", "main", "java"); - File to = new File(sourceDir, "Foo.java"); - File from = new File("src/test/java/com/github/spotbugs/Foo.java"); - Files.copy(from.toPath(), to.toPath(), StandardCopyOption.COPY_ATTRIBUTES); - } - - @Test - public void TestSpotBugsTasksExist() throws Exception{ - BuildResult result = GradleRunner.create() - .withProjectDir(folder.getRoot()) - .withArguments(Arrays.asList("tasks", "--all")) - .withPluginClasspath() - .build(); - assertTrue(result.getOutput().contains("spotbugsMain")); - assertTrue(result.getOutput().contains("spotbugsTest")); - } - - @Test - @Ignore - public void testSpotBugsTaskCanRun() throws Exception { - BuildResult result = GradleRunner.create() - .withProjectDir(folder.getRoot()) - .withArguments(Arrays.asList("compileJava", "spotbugsMain")) - .withPluginClasspath() - .build(); - Optional spotbugsMain = findTask(result, ":spotbugsMain"); - assertTrue(spotbugsMain.isPresent()); - assertThat(spotbugsMain.get().getOutcome(), is(TaskOutcome.SUCCESS)); - assertTrue(new File(folder.getRoot(), "build/reports/spotbugs/main.xml").exists()); - } - - private Optional findTask(BuildResult result, String taskName) { - return result.getTasks().stream() - .filter(task -> task.getPath().equals(taskName)) - .findAny(); - } - -} diff --git a/src/test/java/com/github/spotbugs/MultipleBuildOutputSourceDirsTest.java b/src/test/java/com/github/spotbugs/MultipleBuildOutputSourceDirsTest.java deleted file mode 100644 index 99a54659..00000000 --- a/src/test/java/com/github/spotbugs/MultipleBuildOutputSourceDirsTest.java +++ /dev/null @@ -1,130 +0,0 @@ -package com.github.spotbugs; - -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; -import java.util.Arrays; - -import org.gradle.internal.impldep.org.apache.commons.io.FileUtils; -import org.gradle.testkit.runner.BuildResult; -import org.gradle.testkit.runner.GradleRunner; -import org.gradle.testkit.runner.TaskOutcome; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -/** - * Test's behaviour of the spotbugs plugin when operating with multiple code languages. - *

- * Currently tests for groovy, scala - but changes should apply to kotlin as well. - * - * @author Kevin Mc Tiernan, 23.05.2018, kemc@skagenfondene.no / kevin.tiernan@knowit.no - */ -public class MultipleBuildOutputSourceDirsTest { - - @Rule - public TemporaryFolder folder = new TemporaryFolder(); - - @Before - public void cleanUpProjectFolder() { - final File[] directoryContent = folder.getRoot().listFiles(); - - if (directoryContent != null && directoryContent.length == 0) { - return; - } - - for (File currentFile : directoryContent) { - FileUtils.deleteQuietly(currentFile); - } - } - - @Test - public void testCombinedScalaJavaSources() throws IOException { - // :: Setup - createProjectScala(); - // :: Act - BuildResult result = GradleRunner.create() - .withProjectDir(folder.getRoot()) - .withArguments(Arrays.asList("spotbugsMain")) - .withPluginClasspath() - .forwardOutput() - .build(); - // :: Verify - assertThat(result.task(":spotbugsMain").getOutcome(), is(TaskOutcome.SUCCESS)); - } - - @Test - public void testSingleGroovySource() throws IOException { - // :: Setup - createProjectGroovy(); - // :: Act - BuildResult result = GradleRunner.create() - .withProjectDir(folder.getRoot()) - .withArguments(Arrays.asList("spotbugsMain")) - .withPluginClasspath() - .forwardOutput() - .build(); - // :: Verify - assertThat(result.task(":spotbugsMain").getOutcome(), is(TaskOutcome.SUCCESS)); - } - - @Test - public void testSingleGroovyTestSource() throws IOException { - // :: Setup - createProjectGroovyTest(); - // :: Act - BuildResult result = GradleRunner.create() - .withProjectDir(folder.getRoot()) - .withArguments(Arrays.asList("spotbugsTest")) - .withPluginClasspath() - .forwardOutput() - .build(); - // :: Verify - assertThat(result.task(":spotbugsTest").getOutcome(), is(TaskOutcome.SUCCESS)); - } - - // =========================== Helper methods ===================================================================== - - private void createProjectScala() throws IOException { - Files.copy(Paths.get("src/test/resources/MultipleBuildOutputSourceDirsScala.gradle"), folder.getRoot().toPath().resolve("build.gradle"), - StandardCopyOption.COPY_ATTRIBUTES); - - File javaSourceDir = folder.newFolder("src", "main", "java"); - File to = new File(javaSourceDir, "Foo.java"); - File from = new File("src/test/java/com/github/spotbugs/Foo.java"); - Files.copy(from.toPath(), to.toPath(), StandardCopyOption.COPY_ATTRIBUTES); - } - - private void createProjectGroovy() throws IOException { - Files.copy(Paths.get("src/test/resources/MultipleBuildOutputSourceDirsGroovy.gradle"), folder.getRoot().toPath().resolve("build.gradle"), - StandardCopyOption.COPY_ATTRIBUTES); - - File sourceDir = folder.newFolder("src", "main", "groovy"); - File to = new File(sourceDir, "Bar.groovy"); - File from = new File("src/test/java/com/github/spotbugs/Bar.groovy"); - Files.copy(from.toPath(), to.toPath(), StandardCopyOption.COPY_ATTRIBUTES); - } - - private void createProjectGroovyTest() throws IOException { - Files.copy(Paths.get("src/test/resources/MultipleBuildOutputSourceDirsGroovy.gradle"), folder.getRoot().toPath().resolve("build.gradle"), - StandardCopyOption.COPY_ATTRIBUTES); - - File sourceDirJava = folder.newFolder("src", "main", "java"); - File sourceDirGroovyTest = folder.newFolder("src", "test", "groovy"); - File to = new File(sourceDirJava, "Foo.java"); - File from = new File("src/test/java/com/github/spotbugs/Foo.java"); - - Files.copy(from.toPath(), to.toPath(), StandardCopyOption.COPY_ATTRIBUTES); - - to = new File(sourceDirGroovyTest, "FooTest.groovy"); - from = new File("src/test/java/com/github/spotbugs/FooTest.groovy"); - - Files.copy(from.toPath(), to.toPath(), StandardCopyOption.COPY_ATTRIBUTES); - } -} \ No newline at end of file diff --git a/src/test/java/com/github/spotbugs/MultipleClassDirsTest.java b/src/test/java/com/github/spotbugs/MultipleClassDirsTest.java deleted file mode 100644 index e8ebbac3..00000000 --- a/src/test/java/com/github/spotbugs/MultipleClassDirsTest.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Contributions to SpotBugs - * Copyright (C) 2017, kengo - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -package com.github.spotbugs; - -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; -import java.util.Arrays; - -import org.gradle.testkit.runner.BuildResult; -import org.gradle.testkit.runner.GradleRunner; -import org.gradle.testkit.runner.TaskOutcome; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -public class MultipleClassDirsTest { - @Rule - public TemporaryFolder folder = new TemporaryFolder(); - - @Before - public void createProject() throws IOException { - Files.copy(Paths.get("src/test/resources/MultipleClassDirs.gradle"), folder.getRoot().toPath().resolve("build.gradle"), - StandardCopyOption.COPY_ATTRIBUTES); - - File sourceDir = folder.newFolder("src", "main", "java"); - File to = new File(sourceDir, "Foo.java"); - File from = new File("src/test/java/com/github/spotbugs/Foo.java"); - Files.copy(from.toPath(), to.toPath(), StandardCopyOption.COPY_ATTRIBUTES); - } - - @Test - public void testToEnsurePluginWorksWithMultiClassesDirectories() throws Exception { - BuildResult result = GradleRunner.create().withProjectDir(folder.getRoot()) - .withArguments(Arrays.asList("spotbugsMain")).withPluginClasspath().build(); - assertThat(result.task(":compileJava").getOutcome(), is(TaskOutcome.SUCCESS)); - assertThat(result.task(":classes").getOutcome(), is(TaskOutcome.SUCCESS)); - } -} diff --git a/src/test/java/com/github/spotbugs/SourceAnalysisProperty.java b/src/test/java/com/github/spotbugs/SourceAnalysisProperty.java deleted file mode 100644 index 09fbd5db..00000000 --- a/src/test/java/com/github/spotbugs/SourceAnalysisProperty.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.github.spotbugs; - -/** - * Used by {@link SourceAnalysisPropertyTest} - * as an example of code with a "SwitchFallthrough" deficiency, - * which should be disabled through a SpotBugs analysis property. - */ -public class SourceAnalysisProperty { - - static int method(String someString) { - int result = 5; - - switch (someString) { - case "Hello": - result = 10; - // fall through - - case "Hello, World!": - result += 4; - // fall through - - default: - result += 6; - break; - } - - return result; - } - - public static void main(String[] args) { - System.out.println("result = " + method("Hello, World!")); - } -} diff --git a/src/test/java/com/github/spotbugs/SourceAnalysisPropertyTest.java b/src/test/java/com/github/spotbugs/SourceAnalysisPropertyTest.java deleted file mode 100644 index 2a5bd4bf..00000000 --- a/src/test/java/com/github/spotbugs/SourceAnalysisPropertyTest.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.github.spotbugs; - -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; -import java.util.Arrays; -import java.util.Optional; - -import org.gradle.testkit.runner.BuildResult; -import org.gradle.testkit.runner.BuildTask; -import org.gradle.testkit.runner.GradleRunner; -import org.gradle.testkit.runner.TaskOutcome; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -public class SourceAnalysisPropertyTest { - - @Rule - public final TemporaryFolder folder = new TemporaryFolder(); - - @Before - public void createProject() throws IOException { - Files.copy(Paths.get("src/test/resources/SourceAnalysisProperty.gradle"), folder.getRoot().toPath().resolve("build.gradle"), - StandardCopyOption.COPY_ATTRIBUTES); - - File sourceDir = folder.newFolder("src", "main", "java", "com", "github", "spotbugs"); - File destinationFile = new File(sourceDir, "SourceAnalysisProperty.java"); - File sourceFile = new File("src/test/java/com/github/spotbugs/SourceAnalysisProperty.java"); - Files.copy(sourceFile.toPath(), destinationFile.toPath(), StandardCopyOption.COPY_ATTRIBUTES); - } - - @Test - public void testNotReportingSwitchFallthroughWhenSourceAnalysisPropertySet() { - BuildResult result = GradleRunner.create() - .withProjectDir(folder.getRoot()) - .withDebug(true) - .withArguments(Arrays.asList("compileJava", "spotbugsMain")) - .withPluginClasspath().build(); - Optional spotbugsTest = findTask(result, ":spotbugsMain"); - assertTrue(spotbugsTest.isPresent()); - assertThat(spotbugsTest.get().getOutcome(), is(TaskOutcome.SUCCESS)); - } - - private Optional findTask(BuildResult result, String taskName) { - return result.getTasks().stream() - .filter(task -> task.getPath().equals(taskName)) - .findAny(); - } -} diff --git a/src/test/java/com/github/spotbugs/SpotBugsPluginTest.java b/src/test/java/com/github/spotbugs/SpotBugsPluginTest.java deleted file mode 100644 index 03ef20d4..00000000 --- a/src/test/java/com/github/spotbugs/SpotBugsPluginTest.java +++ /dev/null @@ -1,167 +0,0 @@ -package com.github.spotbugs; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.notNullValue; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; -import java.util.Arrays; -import java.util.Optional; - -import org.gradle.testkit.runner.BuildResult; -import org.gradle.testkit.runner.BuildTask; -import org.gradle.testkit.runner.GradleRunner; -import org.gradle.testkit.runner.TaskOutcome; -import org.gradle.util.GradleVersion; -import org.hamcrest.CoreMatchers; -import org.junit.Assert; -import org.junit.Assume; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -public class SpotBugsPluginTest extends Assert{ - @Rule - public TemporaryFolder folder = new TemporaryFolder(); - - @Before - public void createProject() throws IOException { - Files.copy(Paths.get("src/test/resources/SpotBugsPlugin.gradle"), folder.getRoot().toPath().resolve("build.gradle"), - StandardCopyOption.COPY_ATTRIBUTES); - - File sourceDir = folder.newFolder("src", "main", "java"); - File to = new File(sourceDir, "Foo.java"); - File from = new File("src/test/java/com/github/spotbugs/Foo.java"); - Files.copy(from.toPath(), to.toPath(), StandardCopyOption.COPY_ATTRIBUTES); - } - - @Test - public void TestSpotBugsTasksExist() throws Exception{ - BuildResult result = GradleRunner.create().withProjectDir(folder.getRoot()).withArguments(Arrays.asList("tasks", "--all")).withPluginClasspath().build(); - assertTrue(result.getOutput().contains("spotbugsMain")); - assertTrue(result.getOutput().contains("spotbugsTest")); - } - - @Test - public void testSpotBugsTaskCanRun() throws Exception { - BuildResult result = GradleRunner.create() - .withProjectDir(folder.getRoot()) - .withArguments(Arrays.asList("compileJava", "spotbugsMain")) - .withPluginClasspath().build(); - Optional spotbugsMain = findTask(result, ":spotbugsMain"); - assertTrue(spotbugsMain.isPresent()); - assertThat(spotbugsMain.get().getOutcome(), is(TaskOutcome.SUCCESS)); - } - - /** - * Only run this test under JDK 8. - * - * Skip this test on Java 11 - it simulates a lower Gradle version, - * whose {@link org.gradle.api.JavaVersion} enum may not recognize Java 11 at runtime - * and will fail. - */ - @Test - public void testSpotBugsTaskCanRunWithMinimumSupportedVersion() throws Exception { - Assume.assumeThat(System.getProperty("java.version"), CoreMatchers.startsWith("1.8")); - BuildResult result = GradleRunner.create() - .withProjectDir(folder.getRoot()) - .withArguments(Arrays.asList("compileJava", "spotbugsMain")) - .withPluginClasspath() - .withGradleVersion(SpotBugsPlugin.SUPPORTED_VERSION.getVersion()) - .build(); - Optional spotbugsMain = findTask(result, ":spotbugsMain"); - assertTrue(spotbugsMain.isPresent()); - assertThat(spotbugsMain.get().getOutcome(), is(TaskOutcome.SUCCESS)); - } - - @Test - public void testSpotBugsTestTaskCanRun() throws Exception { - BuildResult result = GradleRunner.create() - .withProjectDir(folder.getRoot()) - .withArguments(Arrays.asList("compileTestJava", "spotbugsTest")) - .withPluginClasspath().build(); - Optional spotbugsTest = findTask(result, ":spotbugsTest"); - assertTrue(spotbugsTest.isPresent()); - assertThat(spotbugsTest.get().getOutcome(), is(TaskOutcome.NO_SOURCE)); - } - - @Test - public void testCheckTaskDependsOnSpotBugsTasks() throws Exception { - BuildResult result = GradleRunner.create() - .withProjectDir(folder.getRoot()) - .withArguments(Arrays.asList("compileJava", "compileTestJava", "check")) - .withPluginClasspath().build(); - assertTrue(findTask(result, ":spotbugsMain").isPresent()); - assertTrue(findTask(result, ":spotbugsTest").isPresent()); - } - - private Optional findTask(BuildResult result, String taskName) { - return result.getTasks().stream() - .filter(task -> task.getPath().equals(taskName)) - .findAny(); - } - - @Test - public void testLoadToolVersion() { - SpotBugsPlugin plugin = new SpotBugsPlugin(); - assertThat(plugin.loadToolVersion(), is(notNullValue())); - } - - @Test(expected = IllegalArgumentException.class) - public void testVersionVerifyForGradleVersion2() { - SpotBugsPlugin plugin = new SpotBugsPlugin(); - plugin.verifyGradleVersion(GradleVersion.version("2.0")); - } - - @Test(expected = IllegalArgumentException.class) - public void testVersionVerifyForGradleVersion3() { - SpotBugsPlugin plugin = new SpotBugsPlugin(); - plugin.verifyGradleVersion(GradleVersion.version("3.0")); - } - - @Test(expected = IllegalArgumentException.class) - public void testVersionVerifyForGradleVersion4() { - SpotBugsPlugin plugin = new SpotBugsPlugin(); - plugin.verifyGradleVersion(GradleVersion.version("4.0")); - } - - @Test(expected = IllegalArgumentException.class) - public void testVersionVerifyForGradleVersion41() { - SpotBugsPlugin plugin = new SpotBugsPlugin(); - plugin.verifyGradleVersion(GradleVersion.version("4.1")); - } - - @Test(expected = IllegalArgumentException.class) - public void testVersionVerifyForGradleVersion42() { - SpotBugsPlugin plugin = new SpotBugsPlugin(); - plugin.verifyGradleVersion(GradleVersion.version("4.2")); - } - - @Test(expected = IllegalArgumentException.class) - public void testVersionVerifyForGradleVersion5() { - SpotBugsPlugin plugin = new SpotBugsPlugin(); - plugin.verifyGradleVersion(GradleVersion.version("5.0")); - } - - @Test(expected = IllegalArgumentException.class) - public void testVersionVerifyForGradleVersion51() { - SpotBugsPlugin plugin = new SpotBugsPlugin(); - plugin.verifyGradleVersion(GradleVersion.version("5.1")); - } - - @Test - public void testVersionVerifyForGradleVersion52() { - SpotBugsPlugin plugin = new SpotBugsPlugin(); - plugin.verifyGradleVersion(GradleVersion.version("5.2")); - } - - @Test - public void testVersionVerifyForGradleVersion53() { - SpotBugsPlugin plugin = new SpotBugsPlugin(); - plugin.verifyGradleVersion(GradleVersion.version("5.3")); - } -} diff --git a/src/test/java/com/github/spotbugs/snom/SpotBugsPluginTest.java b/src/test/java/com/github/spotbugs/snom/SpotBugsPluginTest.java new file mode 100644 index 00000000..dd20a4a7 --- /dev/null +++ b/src/test/java/com/github/spotbugs/snom/SpotBugsPluginTest.java @@ -0,0 +1,53 @@ +/* + * Copyright 2019 SpotBugs team + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.github.spotbugs.snom; + +import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import com.tngtech.archunit.core.domain.JavaClasses; +import com.tngtech.archunit.core.importer.ClassFileImporter; +import com.tngtech.archunit.lang.ArchRule; +import org.gradle.util.GradleVersion; +import org.junit.jupiter.api.Test; + +class SpotBugsPluginTest { + + @Test + void testLoadToolVersion() { + assertNotNull(new SpotBugsBasePlugin().loadProperties().getProperty("spotbugs-version")); + assertNotNull(new SpotBugsBasePlugin().loadProperties().getProperty("slf4j-version")); + } + + @Test + void testVerifyGradleVersion() { + assertThrows( + IllegalArgumentException.class, + () -> { + new SpotBugsBasePlugin().verifyGradleVersion(GradleVersion.version("5.5")); + }); + new SpotBugsBasePlugin().verifyGradleVersion(GradleVersion.version("5.6")); + } + + @Test + void testDependencyOnGradleInternalAPI() { + JavaClasses implementation = + new ClassFileImporter() + .importPackages("com.github.spotbugs.snom", "com.github.spotbugs.snom.internal"); + ArchRule rule = + noClasses().should().dependOnClassesThat().resideInAPackage("org.gradle..internal.."); + rule.check(implementation); + } +} diff --git a/src/test/resources/HtmlReportTest.gradle b/src/test/resources/HtmlReportTest.gradle deleted file mode 100644 index a503a205..00000000 --- a/src/test/resources/HtmlReportTest.gradle +++ /dev/null @@ -1,17 +0,0 @@ -plugins { - id 'java' - id 'com.github.spotbugs' -} -version = '1.2.3' -repositories { - mavenCentral() -} -spotbugsMain { - reports { - xml.enabled false - html { - enabled true - stylesheet 'fancy-hist.xsl' - } - } -} diff --git a/src/test/resources/Issue31.gradle b/src/test/resources/Issue31.gradle deleted file mode 100644 index ebaec9cf..00000000 --- a/src/test/resources/Issue31.gradle +++ /dev/null @@ -1,14 +0,0 @@ -plugins { - id 'java' - id 'com.github.spotbugs' -} -version = 1.0 -repositories { - mavenCentral() -} -spotbugsMain { - reports { - xml.enabled false - text.enabled true - } -} diff --git a/src/test/resources/Issue423.gradle b/src/test/resources/Issue423.gradle deleted file mode 100644 index 9cbce9a9..00000000 --- a/src/test/resources/Issue423.gradle +++ /dev/null @@ -1,14 +0,0 @@ -plugins { - id 'java' - id 'com.github.spotbugs' -} -version = 1.0 -repositories { - mavenCentral() -} -task spotbugs(type: com.github.spotbugs.SpotBugsTask) { - reports { - xml.enabled true - xml.destination ((java.io.File) null) - } -} diff --git a/src/test/resources/Issue440.gradle b/src/test/resources/Issue440.gradle deleted file mode 100644 index 0c25a5fa..00000000 --- a/src/test/resources/Issue440.gradle +++ /dev/null @@ -1,8 +0,0 @@ -plugins { - id 'java' - id 'com.github.spotbugs' -} -version = 1.0 -repositories { - mavenCentral() -} diff --git a/src/test/resources/Issue54.gradle b/src/test/resources/Issue54.gradle deleted file mode 100644 index 3ad903ba..00000000 --- a/src/test/resources/Issue54.gradle +++ /dev/null @@ -1,13 +0,0 @@ -plugins { - id 'java' - id 'com.github.spotbugs' -} -version = 1.0 -repositories { - mavenCentral() -} -spotbugsMain { - classes = classes.filter { - !it.path.contains('com/') - } -} diff --git a/src/test/resources/KotlinBuildScript.gradle.kts b/src/test/resources/KotlinBuildScript.gradle.kts deleted file mode 100644 index ca57c031..00000000 --- a/src/test/resources/KotlinBuildScript.gradle.kts +++ /dev/null @@ -1,11 +0,0 @@ -plugins { - java - id("com.github.spotbugs") -} -version = 1.0 -repositories { - mavenCentral() -} -if (project.hasProperty("ignoreFailures")) { - spotbugs.setIgnoreFailures(true) -} \ No newline at end of file diff --git a/src/test/resources/MultipleBuildOutputSourceDirsGroovy.gradle b/src/test/resources/MultipleBuildOutputSourceDirsGroovy.gradle deleted file mode 100644 index ed8c38d5..00000000 --- a/src/test/resources/MultipleBuildOutputSourceDirsGroovy.gradle +++ /dev/null @@ -1,12 +0,0 @@ -plugins { - id 'java' - id 'groovy' - id 'com.github.spotbugs' -} -version = 1.0 -repositories { - mavenCentral() -} -dependencies { - compile 'org.codehaus.groovy:groovy-all:2.4.14' -} diff --git a/src/test/resources/MultipleBuildOutputSourceDirsScala.gradle b/src/test/resources/MultipleBuildOutputSourceDirsScala.gradle deleted file mode 100644 index 6a454059..00000000 --- a/src/test/resources/MultipleBuildOutputSourceDirsScala.gradle +++ /dev/null @@ -1,20 +0,0 @@ -plugins { - id 'java' - id 'scala' - id 'com.github.spotbugs' -} -version = 1.0 -repositories { - mavenCentral() -} - -apply plugin: 'java' -apply plugin: 'scala' - -sourceSets.main.scala.srcDirs = ['src/main/java', 'src/main/scala'] -sourceSets.main.java.srcDirs = [] - -ext.scalaFullVersion = '2.10.3' -dependencies { - compile 'org.scala-lang:scala-library:2.10.7' -} diff --git a/src/test/resources/MultipleClassDirs.gradle b/src/test/resources/MultipleClassDirs.gradle deleted file mode 100644 index 7e090ed4..00000000 --- a/src/test/resources/MultipleClassDirs.gradle +++ /dev/null @@ -1,9 +0,0 @@ -plugins { - id 'java' - id 'com.github.spotbugs' -} -version = 1.0 -repositories { - mavenCentral() -} -sourceSets.main.output.addClassesDir { -> file('build/classes/java/second') } \ No newline at end of file diff --git a/src/test/resources/SourceAnalysisProperty.gradle b/src/test/resources/SourceAnalysisProperty.gradle deleted file mode 100644 index e03e4057..00000000 --- a/src/test/resources/SourceAnalysisProperty.gradle +++ /dev/null @@ -1,16 +0,0 @@ -plugins { - id 'java' - id 'com.github.spotbugs' -} -version = 1.0 -repositories { - mavenCentral() -} -sourceSets { - main { - java.srcDirs = ['src/main/java'] - } -} -tasks.withType(com.github.spotbugs.SpotBugsTask) { - jvmArgs = ['-Dfindbugs.sf.comment=true'] -} diff --git a/src/test/resources/SpotBugsPlugin.gradle b/src/test/resources/SpotBugsPlugin.gradle deleted file mode 100644 index d7b0d324..00000000 --- a/src/test/resources/SpotBugsPlugin.gradle +++ /dev/null @@ -1,9 +0,0 @@ -plugins { - id 'java' - id 'com.github.spotbugs' -} -version = 1.0 -repositories { - mavenCentral() -} -if(project.hasProperty('ignoreFailures')) { spotbugs.ignoreFailures = true } \ No newline at end of file