[
  {
    "path": ".gitignore",
    "content": "target\n.idea\n.project\n.classpath\n.settings\n*.iml\n/bin/\n/release.properties\n/pom.xml.releaseBackup\n/dependency-reduced-pom.xml\n"
  },
  {
    "path": ".travis/runSonarQubeAnalysis.sh",
    "content": "#!/bin/sh\n# Exit on failure\nset -e\n\n# We don't want to run X times the same analysis because of the matrix configuration\nif [ \"${SQ_RUN}\" != \"yes\" ]; then\n\techo \"Duplicated run detected, skipping the SonarQube analysis...\"\n\texit 0\nfi\n\necho \"Starting analysis by SonarQube...\"\nmvn clean org.jacoco:jacoco-maven-plugin:prepare-agent install sonar:sonar -B -e -V\n"
  },
  {
    "path": ".travis/script.sh",
    "content": "#!/bin/bash\nset -ev\n\nif [ -z \"${TEST_SUITE}\" ]; then\n\techo \"No \\$TEST_SUITE specified, aborting!\"\n\texit 1\n\nelif [ \"unit\" = \"${TEST_SUITE}\" ]; then\n\tmvn -e test -Pcoverage-per-test\n\nelif [ \"integration\" = \"${TEST_SUITE}\" ]; then\n\tif [ -z \"${SONARQUBE_VERSION}\" ]; then\n\t\techo \"No \\$SONARQUBE_VERSION specified, aborting!\"\n\t\texit 1\n\tfi\n\n\ttail -F \"target/fixtures/sonarqube/sonarqube-${SONARQUBE_VERSION}/logs/sonar.log\" &\n\t# otherwise the rails bundled with sonarqube tries to load test.yml which does\n\t# not exist\n\texport RAILS_ENV=production\n\tenv -u SONAR_TOKEN mvn -e verify -Dtest.sonarqube.dist.version=\"${SONARQUBE_VERSION}\"\n\nelif [ \"dependency-check\" = \"${TEST_SUITE}\" ]; then\n\tmvn -e org.owasp:dependency-check-maven:check\n\nfi\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: java\n\nmatrix:\n  fast_finish: true\n  include:\n    # The basic unit-tests environments\n    - jdk: oraclejdk8\n      env:\n        - TEST_SUITE=unit\n        - SQ_RUN=yes\n        # It is necessary only to run the analysis once ;)\n\n    # The integration tests environments\n    - jdk: openjdk8\n      env:\n        - TEST_SUITE=integration\n        - SONARQUBE_VERSION=7.6\n\n    - jdk: openjdk8\n      env:\n        - TEST_SUITE=integration\n        - SONARQUBE_VERSION=6.7\n\n    - jdk: openjdk8\n      env:\n        - TEST_SUITE=dependency-check\n\naddons:\n  sonarcloud:\n    organization: \"default\"\n\n\ninstall:\n  - mvn dependency:go-offline\n\nscript:\n  - ./.travis/script.sh\n  - ./.travis/runSonarQubeAnalysis.sh\n\nsudo: false\ndist: trusty\ngit:\n  depth: false\n\nnotifications:\n  email: false\n\n"
  },
  {
    "path": "LICENSE.md",
    "content": "\n\nThe MIT License (MIT)\n\nCopyright (c) 2015 Amadeus S.A.S., Antoine Copet, Mathieu-Antoine Simon\nCopyright (c) 2016 Amadeus Germany GmbH, Thomas Weißschuh\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n"
  },
  {
    "path": "README.md",
    "content": "# SonarQube Stash (BitBucket) plugin\n\n## Important note\n\nVersion 7.7 of SonarQube [dropped support for the extension point sonar-stash uses](https://jira.sonarsource.com/browse/SONAR-11670).\nThis means this plugin *can not work* on SonarQube versions >= 7.7.\nTherefore the 1.6.0 release is the last feature-release of `sonar-stash`.\n\n\n[![Build Status](https://travis-ci.org/AmadeusITGroup/sonar-stash.svg?branch=master)](https://travis-ci.org/AmadeusITGroup/sonar-stash/branches)\n[![SonarQube Quality Gate](https://sonarcloud.io/api/project_badges/quality_gate?project=org.sonar:sonar-stash-plugin)](https://sonarcloud.io/dashboard?id=org.sonar%3Asonar-stash-plugin)\n[![Unit-Tests Overall Coverage](https://sonarcloud.io/api/project_badges/measure?project=org.sonar:sonar-stash-plugin&metric=coverage)](https://sonarcloud.io/dashboard?id=org.sonar%3Asonar-stash-plugin)\n[![SonarQube Reported Bugs](https://sonarcloud.io/api/project_badges/measure?project=org.sonar:sonar-stash-plugin&metric=bugs)](https://sonarcloud.io/dashboard?id=org.sonar%3Asonar-stash-plugin)\n[![SonarQube Reported Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=org.sonar:sonar-stash-plugin&metric=vulnerabilities)](https://sonarcloud.io/dashboard?id=org.sonar%3Asonar-stash-plugin)\n[![Technical Debt](https://sonarcloud.io/api/project_badges/measure?project=org.sonar:sonar-stash-plugin&metric=sqale_index)](https://sonarcloud.io/dashboard?id=org.sonar%3Asonar-stash-plugin)\n\n**SonarQube is now a real reviewer!**\nSonarQube Stash (BitBucket) plugin is a pull-request decorator which allows to integrate SonarQube violations directly into your pull-request.\n\n![Screenshot SonarQube plugin](resources/Stash-plugin-issues.PNG)\n\nAfter every run, in addition of the diff view, you may access to an overview of your SQ analysis:\n\n![Screenshot SonarQube plugin](resources/Stash-plugin-overview.PNG)\n\n\n## Getting started\n\n#### Prerequisites\n- Git client to checkout the code\n- Maven 3.0.5+\n- JDK 1.8+\n- SonarQube 6.7 (LTS) and 7.6\n- Stash (BitBucket) REST API 1.0 (3.x, 4.x)\n\nNote: these are the versions where the plugin has been tested. Other versions may or may not work, YMMV.\n\n#### To build the plugin\nThis command generates a jar file:\n```\nmvn clean package\n```\n\n#### To deploy the plugin\nJust copy the sonar-stash-plugin jar file to the plugin folder of the expected SonarQube server and restart the SonarQube server. For instance, on Linux platform:\n```\ncp target/sonar-stash-plugin-1.0.jar $SONARQUBE_HOME/extensions/plugins\n```\n\n#### Configuration on SonarQube server\nGo to Stash general settings screen on SonarQube server to fill:\n\n![Screenshot SonarQube plugin](resources/Sonar-plugin-configuration.PNG)\n\n**Stash base URL** (sonar.stash.url): To define Stash instance.\n\n**Stash base user** (sonar.stash.login): To define user to push violations on Stash pull-request. User must have **REPO_READ permission** for the repository. **Please notice Stash password needs to be provided to sonar-runner through sonar.stash.password on the commandline**.\n\n**Stash user slug** (sonar.stash.user.slug): If the user username contains special characters the API requires the use of a different slug.\n\n**Stash issue threshold** (sonar.stash.issue.threshold): To limit the number of issue pushed to Stash.\n\n**Stash issue severity threshold** (sonar.stash.issue.severity.threshold): Defines minimum issue severity to create diff-view comments for. Overview comment will still contain all severities. By default, all issues are pushed to Stash.\n\n**Stash timeout** (sonar.stash.timeout): To timeout when Stash Rest api does not replied with expected.\n\n**Stash reviewer approval** (sonar.stash.reviewer.approval): SonarQube is able to approve the pull-request if there is no new issue introduced by the change. By default, this feature is deactivated: if activated, **Stash base user must have REPO_WRITE permission for the repositories.**\n\n**Approval severity** (sonar.stash.reviewer.approval.severity.threshold): Only approve the pull-request if no issues higher than this threshold are detected.\n\n**Include Analysis Overview Comment** (sonar.stash.include.overview): Toggles whether a comment with overview information should be created.\n\n![Screenshot SonarQube plugin](resources/Sonar-plugin-approver.PNG)\n\n**Stash tasks severity threshold** (sonar.stash.task.issue.severity.threshold): SonarQube is able to create tasks for all issues with a severity higher to the threshold. By default, this feature is deactivated (threshold: NONE). \n\n![Screenshot SonarQube plugin](resources/Stash-plugin-task.PNG)\n\n**Include existing issues** (sonar.stash.include.existing.issues): Toggles whether already existing issues should also be reported.\n\n**Include Vicinity Issues Range** (sonar.stash.include.vicinity.issues.range): Specifies in which area (in lines) around the current diff issues should be reported\n\n**Excluded Rules** (sonar.stash.exclude.rules): Comma separated list of rules for which no comments should be created.\n\n**File names in overview comment**(sonar.stash.overview.filenames): Amount of filenames listed in overview comments\n\n## How to run the plugin?\n\n#### Plugin activation for an analysis\n\nTo activate the plugin, just add the following options to the SonarQube launcher (for instance with sonar-runner):\n\nFor SonarQube 5.2+:\n```\nsonar-runner -Dsonar.analysis.mode=issues \\\n\t-Dsonar.stash.notification=true -Dsonar.stash.project=<PROJECT> -Dsonar.stash.repository=<REPO> \\\n\t-Dsonar.stash.pullrequest.id=<PR_ID> -Dsonar.stash.password=<STASH_PASSWORD>...\n```\n\n#### Repository source configuration\n\nTo tell the plugin about the root directory of your repository use the `sonar.stash.repository.root` property.\nThis is necessary to correlate the the file locations between SonarQube and Stash.\n```\nsonar-runner -Dsonar.stash.repository.root=\"$PWD\" -Dsonar.stash.notification\n```\n\n![Screenshot SonarQube plugin](resources/Stash-plugin-logs.PNG)\n\n#### Reset comments of previous SonarQube analysis\n\nIf needed, you can reset comments published during the previous SonarQube analysis of your pull-request. Please add **sonar.stash.comments.reset** option to your SonarQube analysis. Please notice only comments linked to the **sonar.stash.login** user will be deleted. This reset will be the first action performed by the plugin.\n ```\nsonar-runner -Dsonar.analysis.mode=incremental -Dsonar.stash.notification -Dsonar.stash.comments.reset -Dsonar.stash.project=<PROJECT> -Dsonar.stash.repository=<REPO> -Dsonar.stash.pullrequest.id=<PR_ID> -Dsonar.stash.password=<STASH_PASSWORD>...\n```\n\n## How to activate the coverage inside the pull-request\n\n*This functionality has been moved to its own plugin: https://github.com/AmadeusITGroup/sonar-coverage-evolution*\n\n## Protect passwords\n\nThe plugin can also read the password from an environment variable.\nThis is configured by setting `sonar.stash.password.variable` to the name of\nthe environment variable to read.\nThe prevents the password from leaking into the process table.\n\n# How to contribute\n\n* Before developing a major feature please open a ticket and announce it.\n  Maybe the maintainers have strong opinions or useful hints about it.\n\n* Add unit and for major features integration tests.\n* Use the [Google Java Style Guide](https://google.github.io/styleguide/javaguide.html) for new development.\n"
  },
  {
    "path": "dependency-check-suppression.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<suppressions xmlns=\"https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.1.xsd\">\n  <suppress>\n    <gav regex=\"true\">org\\.asynchttpclient:.*</gav>\n    <cpe>cpe:/a:netty_project:netty</cpe>\n  </suppress>\n  <suppress>\n    <gav regex=\"true\">com\\.typesafe\\.netty:netty-reactive-streams:.*</gav>\n    <cve>CVE-2015-2156</cve>\n    <cve>CVE-2014-3488</cve>\n  </suppress>\n</suppressions>\n"
  },
  {
    "path": "pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n\n  <groupId>org.sonar</groupId>\n  <artifactId>sonar-stash-plugin</artifactId>\n  <version>1.7.0-SNAPSHOT</version>\n  <packaging>sonar-plugin</packaging>\n  <description>Integration between Atlassian Stash (BitBucket) and SonarQube</description>\n  <name>Stash</name>\n  <url>https://github.com/AmadeusITGroup/sonar-stash</url>\n  \n  <licenses>\n    <license>\n      <name>MIT</name>\n      <url>https://opensource.org/licenses/MIT</url>\n      <distribution>repo</distribution>\n    </license>\n  </licenses>\n  \n  <scm>\n    <connection>scm:git:git@github.com:AmadeusITGroup/sonar-stash.git</connection>\n    <developerConnection>scm:git:git@github.com:AmadeusITGroup/sonar-stash.git</developerConnection>\n    <url>https://github.com/AmadeusITGroup/sonar-stash</url>\n    <tag>HEAD</tag>\n  </scm>\n  <issueManagement>\n    <system>GitHub Issues</system>\n    <url>https://github.com/AmadeusITGroup/sonar-stash/issues</url>\n  </issueManagement>\n  <ciManagement>\n    <system>Travis</system>\n    <url>https://travis-ci.org/AmadeusITGroup/sonar-stash</url>\n  </ciManagement>\n\n  <properties>\n    <sonar.version>6.7</sonar.version>\n    <sonar.pluginName>Stash</sonar.pluginName>\n    <sonar.pluginClass>org.sonar.plugins.stash.StashPlugin</sonar.pluginClass>\n    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n\n    <test.sonarqube.dist.groupId>fixme.fixme</test.sonarqube.dist.groupId>\n    <test.sonarqube.dist.artifactId>sonarqube-dist</test.sonarqube.dist.artifactId>\n    <test.sonarqube.dist.version>7.6</test.sonarqube.dist.version>\n    <test.sonarqube.dist.outputdir>${project.build.directory}/fixtures/sonarqube</test.sonarqube.dist.outputdir>\n\n    <test.sonarscanner.dist.groupId>fixme.fixme</test.sonarscanner.dist.groupId>\n    <test.sonarscanner.dist.artifactId>sonarscanner-dist</test.sonarscanner.dist.artifactId>\n    <test.sonarscanner.dist.version>3.3.0.1492</test.sonarscanner.dist.version>\n    <test.sonarscanner.dist.outputdir>${project.build.directory}/fixtures/sonarscanner</test.sonarscanner.dist.outputdir>\n    \n    <test.url.binaries.repo>https://binaries.sonarsource.com/Distribution</test.url.binaries.repo>\n    <test.plugin.archive>${project.build.directory}/${project.artifactId}-${project.version}.jar</test.plugin.archive>\n    <test.sources.dir>${project.build.directory}/fixtures/sources</test.sources.dir>\n    <sonar.coverage.exclusions>src/main/java/org/sonar/plugins/stash/StashPlugin.java,src/main/java/org/sonar/plugins/stash/StashPluginConfiguration.java</sonar.coverage.exclusions>\n  </properties>\n\n  <organization>\n    <name>Amadeus</name>\n    <url>http://www.amadeus.com</url>\n  </organization>\n\n  <dependencyManagement>\n    <dependencies>\n      <dependency>\n        <groupId>org.junit</groupId>\n        <artifactId>junit-bom</artifactId>\n        <version>5.4.0</version>\n        <type>pom</type>\n        <scope>import</scope>\n      </dependency>\n    </dependencies>\n  </dependencyManagement>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.sonarsource.sonarqube</groupId>\n      <artifactId>sonar-plugin-api</artifactId>\n      <version>${sonar.version}</version>\n      <scope>provided</scope>\n    </dependency>\n    <dependency>\n      <groupId>com.github.cliftonlabs</groupId>\n      <artifactId>json-simple</artifactId>\n      <version>3.1.0</version>\n    </dependency>\n    <dependency>\n      <groupId>org.asynchttpclient</groupId>\n      <artifactId>async-http-client</artifactId>\n      <version>2.8.1</version>\n      <exclusions>\n        <exclusion>\n          <groupId>io.netty</groupId>\n          <artifactId>netty-transport-native-epoll</artifactId>\n        </exclusion>\n      </exclusions>\n    </dependency>\n    <dependency>\n      <groupId>com.google.guava</groupId>\n      <artifactId>guava</artifactId>\n      <version>27.0.1-jre</version>\n    </dependency>\n\n    <!-- unit tests -->\n    <dependency>\n      <groupId>org.junit.jupiter</groupId>\n      <artifactId>junit-jupiter-api</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.junit.jupiter</groupId>\n      <artifactId>junit-jupiter-engine</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.assertj</groupId>\n      <artifactId>assertj-core</artifactId>\n      <version>3.11.1</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.mockito</groupId>\n      <artifactId>mockito-core</artifactId>\n      <version>2.25.0</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.mockito</groupId>\n      <artifactId>mockito-junit-jupiter</artifactId>\n      <version>2.25.0</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.awaitility</groupId>\n      <artifactId>awaitility</artifactId>\n      <version>3.1.6</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.slf4j</groupId>\n      <artifactId>slf4j-jdk14</artifactId>\n      <version>1.7.5</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>com.github.tomakehurst</groupId>\n      <artifactId>wiremock</artifactId>\n      <version>2.21.0</version>\n      <scope>test</scope>\n      <exclusions>\n        <exclusion>\n          <groupId>junit</groupId>\n          <artifactId>junit</artifactId>\n        </exclusion>\n      </exclusions>\n    </dependency>\n    <dependency>\n      <groupId>org.picocontainer</groupId>\n      <artifactId>picocontainer</artifactId>\n      <version>2.15</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>com.google.code.gson</groupId>\n      <artifactId>gson</artifactId>\n      <version>2.8.5</version>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n\n  <build>\n    <resources>\n      <resource>\n        <directory>src/main/resources/</directory>\n        <filtering>true</filtering>\n      </resource>\n    </resources>\n    <plugins>\n      <plugin>\n        <groupId>org.sonarsource.sonar-packaging-maven-plugin</groupId>\n        <artifactId>sonar-packaging-maven-plugin</artifactId>\n        <version>1.18.0.372</version>\n        <extensions>true</extensions>\n      </plugin>\n      <plugin>\n        <groupId>org.apache.maven.plugins</groupId>\n        <artifactId>maven-compiler-plugin</artifactId>\n        <version>3.8.0</version>\n        <configuration>\n          <source>1.8</source>\n          <target>1.8</target>\n          <encoding>UTF-8</encoding>\n        </configuration>\n      </plugin>\n      <plugin>\n        <artifactId>maven-resources-plugin</artifactId>\n        <version>3.1.0</version>\n        <configuration>\n          <encoding>UTF-8</encoding>\n        </configuration>\n      </plugin>\n      <plugin>\n        <groupId>org.apache.maven.plugins</groupId>\n        <artifactId>maven-release-plugin</artifactId>\n        <version>2.5.3</version>\n        <configuration>\n          <tagNameFormat>@{project.version}</tagNameFormat>\n          <pushChanges>false</pushChanges>\n        </configuration>\n      </plugin>\n      <plugin>\n        <groupId>com.googlecode.maven-download-plugin</groupId>\n        <artifactId>download-maven-plugin</artifactId>\n        <version>1.3.0</version>\n        <executions>\n          <execution>\n            <id>install-sonarqube</id>\n            <phase>pre-integration-test</phase>\n            <goals>\n              <goal>wget</goal>\n            </goals>\n            <configuration>\n              <url>${test.url.binaries.repo}/sonarqube/sonarqube-${test.sonarqube.dist.version}.zip</url>\n              <unpack>true</unpack>\n              <outputDirectory>${test.sonarqube.dist.outputdir}</outputDirectory>\n            </configuration>\n          </execution>\n          <execution>\n            <id>install-sonarscanner</id>\n            <phase>pre-integration-test</phase>\n            <goals>\n              <goal>wget</goal>\n            </goals>\n            <configuration>\n              <url>${test.url.binaries.repo}/sonar-scanner-cli/sonar-scanner-cli-${test.sonarscanner.dist.version}.zip</url>\n              <unpack>true</unpack>\n              <outputDirectory>${test.sonarscanner.dist.outputdir}</outputDirectory>\n            </configuration>\n          </execution>\n        </executions>\n      </plugin>\n      <plugin>\n        <groupId>org.apache.maven.plugins</groupId>\n        <artifactId>maven-failsafe-plugin</artifactId>\n        <version>3.0.0-M3</version>\n        <executions>\n          <execution>\n            <goals>\n              <goal>integration-test</goal>\n              <goal>verify</goal>\n            </goals>\n          </execution>\n        </executions>\n        <configuration>\n          <trimStackTrace>false</trimStackTrace>\n          <systemPropertyVariables>\n            <test.sonarqube.dist.outputdir>${test.sonarqube.dist.outputdir}</test.sonarqube.dist.outputdir>\n            <test.sonarqube.dist.version>${test.sonarqube.dist.version}</test.sonarqube.dist.version>\n            <test.sonarscanner.dist.outputdir>${test.sonarscanner.dist.outputdir}</test.sonarscanner.dist.outputdir>\n            <test.sonarscanner.dist.version>${test.sonarscanner.dist.version}</test.sonarscanner.dist.version>\n            <test.plugin.archive>${test.plugin.archive}</test.plugin.archive>\n            <test.sources.dir>${test.sources.dir}</test.sources.dir>\n          </systemPropertyVariables>\n        </configuration>\n      </plugin>\n      <plugin>\n        <groupId>org.owasp</groupId>\n        <artifactId>dependency-check-maven</artifactId>\n        <version>4.0.2</version>\n        <configuration>\n          <skipProvidedScope>true</skipProvidedScope>\n          <failBuildOnAnyVulnerability>true</failBuildOnAnyVulnerability>\n          <suppressionFiles>\n            <suppressionFile>dependency-check-suppression.xml</suppressionFile>\n          </suppressionFiles>\n        </configuration>\n      </plugin>\n    </plugins>\n    <pluginManagement>\n      <plugins>\n        <plugin>\n          <groupId>org.apache.maven.plugins</groupId>\n          <artifactId>maven-surefire-plugin</artifactId>\n          <version>3.0.0-M3</version>\n        </plugin>\n      </plugins>\n    </pluginManagement>\n  </build>\n\n  <!-- Profile to activate the code coverage -->\n  <profiles>\n    <profile>\n      <id>coverage-per-test</id>\n      <build>\n        <plugins>\n          <plugin>\n            <groupId>org.apache.maven.plugins</groupId>\n            <artifactId>maven-surefire-plugin</artifactId>\n            <configuration>\n              <properties>\n                <property>\n                  <name>listener</name>\n                  <value>org.sonar.java.jacoco.JUnitListener</value>\n                </property>\n              </properties>\n            </configuration>\n          </plugin>\n          <plugin>\n            <groupId>org.jacoco</groupId>\n            <artifactId>jacoco-maven-plugin</artifactId>\n            <version>0.8.3</version>\n            <executions>\n              <execution>\n                <id>prepare-agent</id>\n                <goals>\n                  <goal>prepare-agent</goal>\n                </goals>\n              </execution>\n            </executions>\n          </plugin>\n        </plugins>\n      </build>\n      <dependencies>\n        <dependency>\n          <groupId>org.sonarsource.java</groupId>\n          <artifactId>sonar-jacoco-listeners</artifactId>\n          <version>5.11.0.17289</version>\n          <scope>test</scope>\n        </dependency>\n      </dependencies>\n    </profile>\n  </profiles>\n</project>\n"
  },
  {
    "path": "src/main/java/org/sonar/plugins/stash/IssuePathResolver.java",
    "content": "package org.sonar.plugins.stash;\n\nimport org.sonar.api.batch.postjob.issue.PostJobIssue;\n\n@FunctionalInterface\npublic interface IssuePathResolver {\n  String getIssuePath(PostJobIssue issue);\n}\n"
  },
  {
    "path": "src/main/java/org/sonar/plugins/stash/PeekableInputStream.java",
    "content": "package org.sonar.plugins.stash;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.PushbackInputStream;\nimport java.util.Optional;\n\npublic class PeekableInputStream extends PushbackInputStream {\n  public PeekableInputStream(InputStream in) {\n    super(in);\n  }\n\n  public Optional<Character> peek() throws IOException {\n    int next = read();\n    if (next == -1) {\n      return Optional.empty();\n    } else {\n      unread(next);\n      return Optional.of(Character.valueOf((char)next));\n    }\n  }\n}\n"
  },
  {
    "path": "src/main/java/org/sonar/plugins/stash/PluginInfo.java",
    "content": "package org.sonar.plugins.stash;\n\npublic class PluginInfo {\n  private String name;\n  private String version;\n\n  public PluginInfo(String name, String version) {\n    this.name = name;\n    this.version = version;\n  }\n\n  public String getVersion() {\n    return version;\n  }\n\n  public String getName() {\n    return name;\n  }\n}\n"
  },
  {
    "path": "src/main/java/org/sonar/plugins/stash/PullRequestRef.java",
    "content": "package org.sonar.plugins.stash;\n\npublic final class PullRequestRef {\n  private String project;\n  private String repository;\n  private int pullRequestId;\n\n  private PullRequestRef(String project, String repository, int pullRequestId) {\n    this.project = project;\n    this.repository = repository;\n    this.pullRequestId = pullRequestId;\n  }\n\n  public String project() {\n    return project;\n  }\n\n  public String repository() {\n    return repository;\n  }\n\n  public int pullRequestId() {\n    return pullRequestId;\n  }\n\n  public static Builder builder() {\n    return new Builder();\n  }\n\n  public static class Builder {\n    private String project;\n    private String repository;\n    private int pullRequestId;\n\n    public Builder setProject(String value) {\n      project = value;\n      return this;\n    }\n\n    public Builder setRepository(String value) {\n      repository = value;\n      return this;\n    }\n\n    public Builder setPullRequestId(int value) {\n      pullRequestId = value;\n      return this;\n    }\n\n    public PullRequestRef build() {\n      return new PullRequestRef(project, repository, pullRequestId);\n    }\n  }\n}\n"
  },
  {
    "path": "src/main/java/org/sonar/plugins/stash/StashIssueReportingPostJob.java",
    "content": "package org.sonar.plugins.stash;\r\n\r\nimport com.google.common.annotations.VisibleForTesting;\r\nimport java.util.Optional;\r\nimport java.util.List;\r\nimport org.sonar.api.batch.InstantiationStrategy;\r\nimport org.sonar.api.batch.ScannerSide;\r\nimport org.sonar.api.batch.postjob.PostJob;\r\nimport org.sonar.api.batch.postjob.PostJobContext;\r\nimport org.sonar.api.batch.postjob.PostJobDescriptor;\r\nimport org.sonar.api.batch.postjob.issue.PostJobIssue;\r\nimport org.sonar.api.batch.rule.Severity;\r\nimport org.sonar.api.platform.Server;\r\nimport org.sonar.api.utils.log.Logger;\r\nimport org.sonar.api.utils.log.Loggers;\r\nimport org.sonar.plugins.stash.client.StashClient;\r\nimport org.sonar.plugins.stash.client.StashCredentials;\r\nimport org.sonar.plugins.stash.exceptions.StashConfigurationException;\r\nimport org.sonar.plugins.stash.exceptions.StashException;\r\nimport org.sonar.plugins.stash.issue.StashDiffReport;\r\nimport org.sonar.plugins.stash.issue.StashUser;\r\n\r\n@ScannerSide\r\n@InstantiationStrategy(InstantiationStrategy.PER_BATCH)\r\npublic class StashIssueReportingPostJob implements PostJob {\r\n\r\n  private static final Logger LOGGER = Loggers.get(StashIssueReportingPostJob.class);\r\n\r\n  private final StashPluginConfiguration config;\r\n  private final StashRequestFacade stashRequestFacade;\r\n  private final Server sonarQubeServer;\r\n\r\n  public StashIssueReportingPostJob(StashPluginConfiguration stashPluginConfiguration,\r\n      StashRequestFacade stashRequestFacade,\r\n      Server sonarQubeServer) {\r\n    this.config = stashPluginConfiguration;\r\n    this.stashRequestFacade = stashRequestFacade;\r\n    this.sonarQubeServer = sonarQubeServer;\r\n  }\r\n\r\n  @Override\r\n  public void execute(PostJobContext context) {\r\n    if (!config.hasToNotifyStash()) {\r\n      LOGGER.info(\"{} not enabled, skipping\", this);\r\n      return;\r\n    }\r\n    try {\r\n      executeThrowing(context);\r\n    } catch (StashException e) {\r\n      LOGGER.error(\"Unable to push SonarQube report to Stash\", e);\r\n    }\r\n  }\r\n\r\n  @VisibleForTesting\r\n  public void executeThrowing(PostJobContext context) {\r\n      String stashURL = stashRequestFacade.getStashURL();\r\n      int stashTimeout = config.getStashTimeout();\r\n\r\n      StashCredentials stashCredentials = stashRequestFacade.getCredentials();\r\n\r\n      try (StashClient stashClient = new StashClient(stashURL,\r\n          stashCredentials,\r\n          stashTimeout,\r\n          sonarQubeServer.getVersion())) {\r\n\r\n        // Down the rabbit hole...\r\n        updateStashWithSonarInfo(stashClient, stashCredentials, context.issues());\r\n      }\r\n  }\r\n\r\n\r\n  /*\r\n  * Second part of the code necessary for the executeOn() -- squid:S134\r\n  */\r\n  private void updateStashWithSonarInfo(StashClient stashClient,\r\n      StashCredentials stashCredentials, Iterable<PostJobIssue> issues) {\r\n\r\n      int issueThreshold = stashRequestFacade.getIssueThreshold();\r\n      PullRequestRef pr = stashRequestFacade.getPullRequest();\r\n\r\n      // SonarQube objects\r\n      List<PostJobIssue> issueReport = stashRequestFacade.extractIssueReport(issues);\r\n\r\n      StashUser stashUser = stashRequestFacade\r\n          .getSonarQubeReviewer(stashCredentials.getUserSlug(), stashClient);\r\n\r\n      if (stashUser == null) {\r\n        throw new StashConfigurationException(\r\n            \"No SonarQube reviewer identified to publish to Stash the SQ analysis\");\r\n      }\r\n\r\n      // Get all changes exposed from Stash differential view of the pull-request\r\n      StashDiffReport diffReport = stashRequestFacade.getPullRequestDiffReport(pr, stashClient);\r\n      if (diffReport == null) {\r\n        throw new StashConfigurationException(\r\n            \"No Stash differential report available to process the SQ analysis\");\r\n      }\r\n\r\n      // if requested, reset all comments linked to the pull-request\r\n      if (config.resetComments()) {\r\n        stashRequestFacade.resetComments(pr, diffReport, stashUser, stashClient);\r\n      }\r\n\r\n      boolean canApprovePullrequest = config.canApprovePullRequest();\r\n      if (canApprovePullrequest) {\r\n        stashRequestFacade.addPullRequestReviewer(pr, stashCredentials.getUserSlug(), stashClient);\r\n      }\r\n\r\n      postInfoAndPRsActions(pr, issueReport, issueThreshold, diffReport, stashClient);\r\n\r\n  }\r\n\r\n\r\n  /*\r\n  * Second part of the code necessary for the updateStashWithSonarInfo() method\r\n  *   and third part of the executeOn() method (call of a call) -- squid:MethodCyclomaticComplexity\r\n  */\r\n  private void postInfoAndPRsActions(\r\n      PullRequestRef pr, List<PostJobIssue> issueReport, int issueThreshold,\r\n      StashDiffReport diffReport, StashClient stashClient\r\n  ) {\r\n\r\n    int issueTotal = issueReport.size();\r\n\r\n    // if threshold exceeded, do not push issue list to Stash\r\n    if (issueTotal >= issueThreshold) {\r\n      LOGGER.warn(\"Too many issues detected ({}/{}): Issues cannot be displayed in Diff view\",\r\n          issueTotal, issueThreshold);\r\n    } else {\r\n      stashRequestFacade.postSonarQubeReport(pr, issueReport, diffReport, stashClient);\r\n    }\r\n\r\n    if (config.includeAnalysisOverview()) {\r\n      stashRequestFacade.postAnalysisOverview(pr, issueReport, stashClient);\r\n    }\r\n\r\n    if (config.canApprovePullRequest()) {\r\n      if (shouldApprovePullRequest(config.getApprovalSeverityThreshold(), issueReport)) {\r\n        stashRequestFacade.approvePullRequest(pr, stashClient);\r\n      } else {\r\n        stashRequestFacade.resetPullRequestApproval(pr, stashClient);\r\n      }\r\n    }\r\n  }\r\n\r\n  static boolean shouldApprovePullRequest(Optional<Severity> approvalSeverityThreshold, List<PostJobIssue> report) {\r\n    if (approvalSeverityThreshold.isPresent()) {\r\n      return report.stream().noneMatch(issue ->\r\n          issue.severity().compareTo(approvalSeverityThreshold.get()) > 0\r\n      );\r\n    }\r\n\r\n    return report.isEmpty();\r\n  }\r\n\r\n  @Override\r\n  public void describe(PostJobDescriptor descriptor) {\r\n    descriptor.requireProperty(StashPlugin.STASH_NOTIFICATION);\r\n    descriptor.name(\"Stash/Bitbucket notification\");\r\n  }\r\n}\r\n"
  },
  {
    "path": "src/main/java/org/sonar/plugins/stash/StashPlugin.java",
    "content": "package org.sonar.plugins.stash;\r\n\r\nimport com.google.common.collect.Lists;\r\nimport java.util.Arrays;\r\nimport java.util.stream.Collectors;\r\nimport org.sonar.api.Plugin;\r\nimport org.sonar.api.Properties;\r\nimport org.sonar.api.Property;\r\nimport org.sonar.api.PropertyType;\r\nimport org.sonar.api.batch.rule.Severity;\r\nimport org.sonar.api.config.PropertyDefinition;\r\nimport org.sonar.api.resources.Qualifiers;\r\n\r\nimport java.util.List;\r\nimport org.sonar.plugins.stash.issue.StashDiffReport;\r\n\r\n@Properties({\r\n                @Property(key = StashPlugin.STASH_NOTIFICATION,\r\n                          name = \"Stash Notification\",\r\n                          defaultValue = \"false\",\r\n                          description = \"Analysis result will be issued in Stash pull request\",\r\n                          global = false),\r\n                @Property(key = StashPlugin.STASH_PROJECT,\r\n                          name = \"Stash Project\",\r\n                          description = \"Stash project of current pull-request\",\r\n                          global = false),\r\n                @Property(key = StashPlugin.STASH_REPOSITORY,\r\n                          name = \"Stash Repository\",\r\n                          description = \"Stash project of current pull-request\",\r\n                          global = false),\r\n                @Property(key = StashPlugin.STASH_PULL_REQUEST_ID,\r\n                          name = \"Stash Pull-request Id\",\r\n                          description = \"Stash pull-request Id\",\r\n                          global = false)})\r\n\r\npublic class StashPlugin implements Plugin {\r\n\r\n  private static final String DEFAULT_STASH_TIMEOUT_VALUE = \"10000\";\r\n  private static final String DEFAULT_STASH_THRESHOLD_VALUE = \"100\";\r\n  private static final boolean DEFAULT_STASH_ANALYSIS_OVERVIEW = true;\r\n  private static final boolean DEFAULT_STASH_INCLUDE_EXISTING_ISSUES = false;\r\n  private static final int DEFAULT_STASH_FILES_IN_OVERVIEW = 0;\r\n  private static final int DEFAULT_STASH_INCLUDE_VICINITY_RANGE = StashDiffReport.VICINITY_RANGE_NONE;\r\n  private static final String DEFAULT_STASH_EXCLUDE_RULES = \"\";\r\n\r\n  private static final String CONFIG_PAGE_SUB_CATEGORY_STASH = \"Stash\";\r\n\r\n  public static final String SEVERITY_NONE = \"NONE\";\r\n\r\n  private static final List<String> SEVERITY_LIST = Arrays.stream(Severity.values())\r\n      .map(Severity::name).collect(Collectors.toList());\r\n  private static final List<String> SEVERITY_LIST_WITH_NONE = Lists\r\n      .asList(SEVERITY_NONE, SEVERITY_LIST.toArray(new String[]{}));\r\n\r\n  public enum IssueType {\r\n    CONTEXT,\r\n    REMOVED,\r\n    ADDED,\r\n  }\r\n\r\n  public static final String STASH_NOTIFICATION = \"sonar.stash.notification\";\r\n  public static final String STASH_PROJECT = \"sonar.stash.project\";\r\n  public static final String STASH_REPOSITORY = \"sonar.stash.repository\";\r\n  public static final String STASH_PULL_REQUEST_ID = \"sonar.stash.pullrequest.id\";\r\n  public static final String STASH_RESET_COMMENTS = \"sonar.stash.comments.reset\";\r\n  public static final String STASH_URL = \"sonar.stash.url\";\r\n  public static final String STASH_LOGIN = \"sonar.stash.login\";\r\n  public static final String STASH_USER_SLUG = \"sonar.stash.user.slug\";\r\n  public static final String STASH_PASSWORD = \"sonar.stash.password\";\r\n  public static final String STASH_PASSWORD_ENVIRONMENT_VARIABLE = \"sonar.stash.password.variable\";\r\n  public static final String STASH_REVIEWER_APPROVAL = \"sonar.stash.reviewer.approval\";\r\n  public static final String STASH_REVIEWER_APPROVAL_SEVERITY_THRESHOLD = \"sonar.stash.reviewer.approval.severity.threshold\";\r\n  public static final String STASH_ISSUE_THRESHOLD = \"sonar.stash.issue.threshold\";\r\n  public static final String STASH_ISSUE_SEVERITY_THRESHOLD = \"sonar.stash.issue.severity.threshold\";\r\n  public static final String STASH_TIMEOUT = \"sonar.stash.timeout\";\r\n  public static final String STASH_TASK_SEVERITY_THRESHOLD = \"sonar.stash.task.issue.severity.threshold\";\r\n  public static final String STASH_INCLUDE_ANALYSIS_OVERVIEW = \"sonar.stash.include.overview\";\r\n  public static final String STASH_REPOSITORY_ROOT = \"sonar.stash.repository.root\";\r\n  public static final String STASH_INCLUDE_EXISTING_ISSUES = \"sonar.stash.include.existing.issues\";\r\n  public static final String STASH_FILES_LIMIT_IN_OVERVIEW = \"sonar.stash.overview.filenames\";\r\n  public static final String STASH_INCLUDE_VICINITY_RANGE = \"sonar.stash.include.vicinity.issues.range\";\r\n  public static final String STASH_EXCLUDE_RULES = \"sonar.stash.exclude.rules\";\r\n\r\n  @Override\r\n  public void define(Context context) {\r\n    context.addExtensions(\r\n        StashIssueReportingPostJob.class,\r\n        StashPluginConfiguration.class,\r\n        StashRequestFacade.class,\r\n        StashProjectBuilder.class,\r\n        PropertyDefinition.builder(STASH_URL)\r\n                          .name(\"Stash base URL\")\r\n                          .description(\"HTTP URL of Stash instance, such as http://yourhost.yourdomain/stash\")\r\n                          .subCategory(CONFIG_PAGE_SUB_CATEGORY_STASH)\r\n                          .onQualifiers(Qualifiers.PROJECT).build(),\r\n        PropertyDefinition.builder(STASH_LOGIN)\r\n                          .name(\"Stash base User\")\r\n                          .description(\"User to push data on Stash instance\")\r\n                          .subCategory(CONFIG_PAGE_SUB_CATEGORY_STASH)\r\n                          .onQualifiers(Qualifiers.PROJECT).build(),\r\n        PropertyDefinition.builder(STASH_USER_SLUG)\r\n                          .name(\"Stash base user slug\")\r\n                          .description(\"If the username has special characters this setting has also to be specified\")\r\n                          .subCategory(CONFIG_PAGE_SUB_CATEGORY_STASH)\r\n                          .onlyOnQualifiers(Qualifiers.PROJECT).build(),\r\n        PropertyDefinition.builder(STASH_PASSWORD)\r\n                          .name(\"Stash base Password\")\r\n                          .description(\"Password for Stash base User (Do NOT use in production, passwords are public\"\r\n                                      + \" for everyone with UNAUTHENTICATED HTTP access to SonarQube\")\r\n                          .type(PropertyType.PASSWORD)\r\n                          .subCategory(CONFIG_PAGE_SUB_CATEGORY_STASH)\r\n                          .onQualifiers(Qualifiers.PROJECT).build(),\r\n        PropertyDefinition.builder(STASH_TIMEOUT)\r\n                          .name(\"Stash issue Timeout\")\r\n                          .description(\"Timeout when pushing a new issue to Stash (in ms)\")\r\n                          .subCategory(CONFIG_PAGE_SUB_CATEGORY_STASH)\r\n                          .onQualifiers(Qualifiers.PROJECT)\r\n                          .defaultValue(DEFAULT_STASH_TIMEOUT_VALUE).build(),\r\n        PropertyDefinition.builder(STASH_REVIEWER_APPROVAL)\r\n                          .name(\"Stash reviewer approval\")\r\n                          .description(\"Does SonarQube approve the pull-request if there is no new issues?\")\r\n                          .subCategory(CONFIG_PAGE_SUB_CATEGORY_STASH)\r\n                          .onQualifiers(Qualifiers.PROJECT)\r\n                          .type(PropertyType.BOOLEAN)\r\n                          .defaultValue(\"false\").build(),\r\n        PropertyDefinition.builder(STASH_ISSUE_THRESHOLD)\r\n                          .name(\"Stash issue Threshold\")\r\n                          .description(\"Threshold to limit the number of issues pushed to Stash server\")\r\n                          .subCategory(CONFIG_PAGE_SUB_CATEGORY_STASH)\r\n                          .onQualifiers(Qualifiers.PROJECT)\r\n                          .defaultValue(DEFAULT_STASH_THRESHOLD_VALUE).build(),\r\n        PropertyDefinition.builder(STASH_ISSUE_SEVERITY_THRESHOLD)\r\n                          .name(\"Stash issue severity Threshold\")\r\n                          .description(\"Defines minimum issue severity to create diff-view comments for.\"\r\n                                  + \" Overview comment will still contain all severities.\"\r\n                                  + \" By default, all issues are pushed to Stash.\")\r\n                          .type(PropertyType.SINGLE_SELECT_LIST)\r\n                          .subCategory(CONFIG_PAGE_SUB_CATEGORY_STASH)\r\n                          .onQualifiers(Qualifiers.PROJECT)\r\n                          .defaultValue(SEVERITY_LIST.get(0))\r\n                          .options(SEVERITY_LIST).build(),\r\n        PropertyDefinition.builder(STASH_REVIEWER_APPROVAL_SEVERITY_THRESHOLD)\r\n                          .name(\"Threshold tie the approval to the severity of the found issues\")\r\n                          .description(\"Maximum severity of an issue for approval to complete\")\r\n                          .type(PropertyType.SINGLE_SELECT_LIST)\r\n                          .subCategory(CONFIG_PAGE_SUB_CATEGORY_STASH)\r\n                          .onQualifiers(Qualifiers.PROJECT)\r\n                          .defaultValue(SEVERITY_NONE)\r\n                          .options(SEVERITY_LIST_WITH_NONE).build(),\r\n        PropertyDefinition.builder(STASH_TASK_SEVERITY_THRESHOLD)\r\n                          .name(\"Stash tasks severity threshold\")\r\n                          .description(\"Only create tasks for issues with the same or higher severity\")\r\n                          .type(PropertyType.SINGLE_SELECT_LIST)\r\n                          .subCategory(CONFIG_PAGE_SUB_CATEGORY_STASH)\r\n                          .onQualifiers(Qualifiers.PROJECT)\r\n                          .defaultValue(SEVERITY_NONE)\r\n                          .options(SEVERITY_LIST_WITH_NONE).build(),\r\n        PropertyDefinition.builder(STASH_INCLUDE_ANALYSIS_OVERVIEW)\r\n                          .name(\"Include Analysis Overview Comment\")\r\n                          .description(\"Create a comment to the Pull Request providing a overview of the results\")\r\n                          .type(PropertyType.BOOLEAN)\r\n                          .subCategory(CONFIG_PAGE_SUB_CATEGORY_STASH)\r\n                          .onQualifiers(Qualifiers.PROJECT)\r\n                          .defaultValue(Boolean.toString(DEFAULT_STASH_ANALYSIS_OVERVIEW)).build(),\r\n        PropertyDefinition.builder(STASH_FILES_LIMIT_IN_OVERVIEW)\r\n                          .name(\"Include Files in Overview\")\r\n                          .description(\"Will extend the Analysis Overview comment to include the files where the \" +\r\n                                  \"issues where found. Set to any positive number to limit how many files per issue \" +\r\n                                  \"will be shown. Set to 0 to disable this feature.\")\r\n                          .type(PropertyType.INTEGER)\r\n                          .subCategory(CONFIG_PAGE_SUB_CATEGORY_STASH)\r\n                          .onQualifiers(Qualifiers.PROJECT)\r\n                          .defaultValue(String.valueOf(DEFAULT_STASH_FILES_IN_OVERVIEW)).build(),\r\n        PropertyDefinition.builder(STASH_INCLUDE_EXISTING_ISSUES)\r\n                          .name(\"Include Existing Issues\")\r\n                          .description(\"Set to true to include already existing issues on modified lines.\")\r\n                          .type(PropertyType.BOOLEAN)\r\n                          .subCategory(CONFIG_PAGE_SUB_CATEGORY_STASH)\r\n                          .onQualifiers(Qualifiers.PROJECT)\r\n                          .defaultValue(Boolean.toString(DEFAULT_STASH_INCLUDE_EXISTING_ISSUES)).build(),\r\n        PropertyDefinition.builder(STASH_INCLUDE_VICINITY_RANGE)\r\n                          .name(\"Include Vicinity Issues Range\")\r\n                          .description(\"Specifies the range around the actual changes for which issues are reported. (In lines)\")\r\n                          .type(PropertyType.INTEGER)\r\n                          .subCategory(CONFIG_PAGE_SUB_CATEGORY_STASH)\r\n                          .onQualifiers(Qualifiers.PROJECT)\r\n                          .defaultValue(String.valueOf(DEFAULT_STASH_INCLUDE_VICINITY_RANGE)).build(),\r\n        PropertyDefinition.builder(STASH_EXCLUDE_RULES)\r\n                          .name(\"Excluded Rules\")\r\n                          .description(\"Comma separated list of rules for which no comments should be created.\")\r\n                          .type(PropertyType.STRING)\r\n                          .subCategory(CONFIG_PAGE_SUB_CATEGORY_STASH)\r\n                          .onQualifiers(Qualifiers.PROJECT)\r\n                          .defaultValue(DEFAULT_STASH_EXCLUDE_RULES).build()\r\n    );\r\n  }\r\n}\r\n\r\n"
  },
  {
    "path": "src/main/java/org/sonar/plugins/stash/StashPluginConfiguration.java",
    "content": "package org.sonar.plugins.stash;\r\n\r\nimport com.google.common.collect.Sets;\r\nimport java.util.Objects;\r\nimport java.util.Set;\r\nimport java.util.stream.Collectors;\r\nimport org.sonar.api.CoreProperties;\r\nimport org.sonar.api.batch.InstantiationStrategy;\r\nimport org.sonar.api.batch.ScannerSide;\r\nimport org.sonar.api.batch.rule.Severity;\r\nimport org.sonar.api.config.Settings;\r\n\r\nimport java.io.File;\r\nimport java.util.Optional;\r\nimport org.sonar.api.platform.Server;\r\nimport org.sonar.api.rule.RuleKey;\r\n\r\n@ScannerSide\r\n@InstantiationStrategy(InstantiationStrategy.PER_BATCH)\r\npublic class StashPluginConfiguration {\r\n\r\n  private Settings settings;\r\n  private Server server;\r\n\r\n  public StashPluginConfiguration(Settings settings, Server server) {\r\n    this.settings = settings;\r\n    this.server = server;\r\n  }\r\n\r\n  public boolean hasToNotifyStash() {\r\n    return settings.getBoolean(StashPlugin.STASH_NOTIFICATION);\r\n  }\r\n\r\n  public String getStashProject() {\r\n    return settings.getString(StashPlugin.STASH_PROJECT);\r\n  }\r\n\r\n  public String getStashRepository() {\r\n    return settings.getString(StashPlugin.STASH_REPOSITORY);\r\n  }\r\n\r\n  public Integer getPullRequestId() {\r\n    return settings.getInt(StashPlugin.STASH_PULL_REQUEST_ID);\r\n  }\r\n\r\n  public String getStashURL() {\r\n    return settings.getString(StashPlugin.STASH_URL);\r\n  }\r\n\r\n  public String getStashLogin() {\r\n    return settings.getString(StashPlugin.STASH_LOGIN);\r\n  }\r\n\r\n  public String getStashUserSlug() {\r\n    return settings.getString(StashPlugin.STASH_USER_SLUG);\r\n  }\r\n\r\n  public String getStashPassword() {\r\n    return settings.getString(StashPlugin.STASH_PASSWORD);\r\n  }\r\n\r\n  public String getStashPasswordEnvironmentVariable() {\r\n    return settings.getString(StashPlugin.STASH_PASSWORD_ENVIRONMENT_VARIABLE);\r\n  }\r\n\r\n  public String getSonarQubeURL() {\r\n    return server.getURL();\r\n  }\r\n\r\n  public String getSonarQubeLogin() {\r\n    return settings.getString(CoreProperties.LOGIN);\r\n  }\r\n\r\n  public String getSonarQubePassword() {\r\n    return settings.getString(CoreProperties.PASSWORD);\r\n  }\r\n\r\n  public int getIssueThreshold() {\r\n    return settings.getInt(StashPlugin.STASH_ISSUE_THRESHOLD);\r\n  }\r\n\r\n  public Severity getIssueSeverityThreshold() {\r\n    return Severity.valueOf(\r\n        Objects.requireNonNull(settings.getString(StashPlugin.STASH_ISSUE_SEVERITY_THRESHOLD)));\r\n  }\r\n\r\n  public int getStashTimeout() {\r\n    return settings.getInt(StashPlugin.STASH_TIMEOUT);\r\n  }\r\n\r\n  public boolean canApprovePullRequest() {\r\n    return settings.getBoolean(StashPlugin.STASH_REVIEWER_APPROVAL);\r\n  }\r\n\r\n  public boolean resetComments() {\r\n    return settings.getBoolean(StashPlugin.STASH_RESET_COMMENTS);\r\n  }\r\n\r\n  public Optional<Severity> getTaskIssueSeverityThreshold() {\r\n    return getOptionalSeveritySetting(StashPlugin.STASH_TASK_SEVERITY_THRESHOLD);\r\n  }\r\n\r\n  public Optional<Severity> getApprovalSeverityThreshold() {\r\n    return getOptionalSeveritySetting(StashPlugin.STASH_REVIEWER_APPROVAL_SEVERITY_THRESHOLD);\r\n  }\r\n\r\n  public boolean includeAnalysisOverview() {\r\n    return settings.getBoolean(StashPlugin.STASH_INCLUDE_ANALYSIS_OVERVIEW);\r\n  }\r\n\r\n  public Optional<File> getRepositoryRoot() {\r\n    return Optional.ofNullable(settings.getString(StashPlugin.STASH_REPOSITORY_ROOT)).map(File::new);\r\n  }\r\n\r\n  public boolean includeExistingIssues() {\r\n    return settings.getBoolean(StashPlugin.STASH_INCLUDE_EXISTING_ISSUES);\r\n  }\r\n\r\n  public int getFilesLimitInOverview() {\r\n    return settings.getInt(StashPlugin.STASH_FILES_LIMIT_IN_OVERVIEW);\r\n  }\r\n\r\n  public int issueVicinityRange() {\r\n    return settings.getInt(StashPlugin.STASH_INCLUDE_VICINITY_RANGE);\r\n  }\r\n\r\n  public Set<RuleKey> excludedRules() {\r\n    return Sets.newHashSet(\r\n        settings.getStringArray(StashPlugin.STASH_EXCLUDE_RULES)\r\n    ).stream()\r\n        .map(String::trim)\r\n        .map(RuleKey::parse)\r\n        .collect(Collectors.toSet());\r\n  }\r\n\r\n  private Optional<Severity> getOptionalSeveritySetting(String key) {\r\n    String setting = settings.getString(key);\r\n    if (StashPlugin.SEVERITY_NONE.equals(setting)) {\r\n      return Optional.empty();\r\n    }\r\n    if (setting == null) {\r\n      return Optional.empty();\r\n    }\r\n    return Optional.of(Severity.valueOf(setting));\r\n  }\r\n}\r\n"
  },
  {
    "path": "src/main/java/org/sonar/plugins/stash/StashPluginUtils.java",
    "content": "package org.sonar.plugins.stash;\r\n\r\nimport com.google.common.base.CharMatcher;\r\nimport java.io.IOException;\r\nimport java.util.Collection;\r\nimport java.util.Properties;\r\nimport org.sonar.api.batch.fs.InputComponent;\r\nimport org.sonar.api.batch.fs.InputModule;\r\nimport org.sonar.api.batch.postjob.issue.PostJobIssue;\r\n\r\nimport java.math.RoundingMode;\r\nimport java.text.DecimalFormat;\r\nimport java.text.DecimalFormatSymbols;\r\nimport org.sonar.api.batch.rule.Severity;\r\n\r\npublic final class StashPluginUtils {\r\n\r\n  private StashPluginUtils() {}\r\n\r\n  public static String formatPercentage(double d) {\r\n\r\n    // Defining that our percentage is precise down to 0.1%\r\n    DecimalFormat df = new DecimalFormat(\"0.0\");\r\n\r\n    // Protecting this method against non-US locales that would not use '.' as decimal separation\r\n    DecimalFormatSymbols decimalFormatSymbols = new DecimalFormatSymbols();\r\n    decimalFormatSymbols.setDecimalSeparator('.');\r\n    df.setDecimalFormatSymbols(decimalFormatSymbols);\r\n\r\n    // Making sure that we round the 0.1% properly out of the double value\r\n    df.setRoundingMode(RoundingMode.HALF_UP);\r\n    return df.format(d);\r\n  }\r\n\r\n  public static boolean roundedPercentageGreaterThan(double left, double right) {\r\n    return (left > right) && !formatPercentage(left).equals(formatPercentage(right));\r\n  }\r\n\r\n  public static long countIssuesBySeverity(Collection<PostJobIssue> issues, final Severity severity) {\r\n    return issues.stream().filter(i -> severity.equals(i.severity())).count();\r\n  }\r\n\r\n  public static boolean isProjectWide(PostJobIssue issue) {\r\n    InputComponent ic = issue.inputComponent();\r\n    if (!(ic instanceof InputModule)) {\r\n      return false;\r\n    }\r\n    InputModule im = (InputModule) ic;\r\n    if (im.key() == null) {\r\n      return false;\r\n    }\r\n    return CharMatcher.is(':').countIn(im.key()) == 0;\r\n  }\r\n\r\n  public static PluginInfo getPluginInfo() {\r\n    Properties props = new Properties();\r\n    try {\r\n      props.load(StashPluginUtils.class.getClassLoader().getResourceAsStream(\"org/sonar/plugins/stash/sonar-stash.properties\"));\r\n    } catch (IOException e) {\r\n      throw new IllegalStateException(e);\r\n    }\r\n\r\n    return new PluginInfo(\r\n        props.getProperty(\"project.name\"),\r\n        props.getProperty(\"project.version\")\r\n    );\r\n  }\r\n\r\n  public static String removeEnd(String s, String suffix) {\r\n    if (s.endsWith(suffix)) {\r\n      return removeEnd(s.substring(0, s.length() - suffix.length()), suffix);\r\n    }\r\n    return s;\r\n  }\r\n}\r\n"
  },
  {
    "path": "src/main/java/org/sonar/plugins/stash/StashProjectBuilder.java",
    "content": "package org.sonar.plugins.stash;\n\nimport org.sonar.api.batch.bootstrap.ProjectBuilder;\n\nimport java.io.File;\n\n// FIXME when we depend on 7.0 and use ScmProvider.relativePathFromScmRoot\npublic class StashProjectBuilder extends ProjectBuilder {\n  private File projectBaseDir;\n\n  @Override\n  public void build(Context context) {\n    projectBaseDir = context.projectReactor().getRoot().getBaseDir();\n  }\n\n  public File getProjectBaseDir() {\n    return projectBaseDir;\n  }\n\n}\n"
  },
  {
    "path": "src/main/java/org/sonar/plugins/stash/StashRequestFacade.java",
    "content": "package org.sonar.plugins.stash;\n\nimport java.io.File;\nimport java.nio.file.Path;\nimport java.util.Collection;\nimport java.util.Optional;\nimport java.text.MessageFormat;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport org.sonar.api.batch.InstantiationStrategy;\nimport org.sonar.api.batch.ScannerSide;\nimport org.sonar.api.batch.fs.InputComponent;\nimport org.sonar.api.batch.fs.InputFile;\nimport org.sonar.api.batch.postjob.issue.PostJobIssue;\nimport org.sonar.api.batch.rule.Severity;\nimport org.sonar.api.scan.filesystem.PathResolver;\nimport org.sonar.api.utils.System2;\nimport org.sonar.api.utils.log.Logger;\nimport org.sonar.api.utils.log.Loggers;\nimport org.sonar.plugins.stash.StashPlugin.IssueType;\nimport org.sonar.plugins.stash.client.StashClient;\nimport org.sonar.plugins.stash.client.StashCredentials;\nimport org.sonar.plugins.stash.exceptions.StashConfigurationException;\nimport org.sonar.plugins.stash.issue.MarkdownPrinter;\nimport org.sonar.plugins.stash.issue.StashComment;\nimport org.sonar.plugins.stash.issue.StashCommentReport;\nimport org.sonar.plugins.stash.issue.StashDiffReport;\nimport org.sonar.plugins.stash.issue.StashPullRequest;\nimport org.sonar.plugins.stash.issue.StashTask;\nimport org.sonar.plugins.stash.issue.StashUser;\nimport org.sonar.plugins.stash.issue.collector.SonarQubeCollector;\n\n@ScannerSide\n@InstantiationStrategy(InstantiationStrategy.PER_BATCH)\npublic class StashRequestFacade implements IssuePathResolver {\n\n  private static final Logger LOGGER = Loggers.get(StashRequestFacade.class);\n\n  private static final String EXCEPTION_STASH_CONF = \"Unable to get {0} from plugin configuration (value is null)\";\n\n  private final StashPluginConfiguration config;\n  private final File projectBaseDir;\n  private final System2 system;\n\n  public StashRequestFacade(\n      StashPluginConfiguration stashPluginConfiguration,\n      StashProjectBuilder projectBuilder,\n      System2 system\n  ) {\n    this.config = stashPluginConfiguration;\n    this.projectBaseDir = projectBuilder.getProjectBaseDir();\n    this.system = system;\n  }\n\n  public List<PostJobIssue> extractIssueReport(Iterable<PostJobIssue> issues) {\n    return SonarQubeCollector.extractIssueReport(\n        issues, this, config.includeExistingIssues(), config.excludedRules()\n    );\n  }\n\n  private MarkdownPrinter getMarkdownPrinter() {\n    return new MarkdownPrinter(getIssueThreshold(), config.getSonarQubeURL(), config.getFilesLimitInOverview(), this);\n  }\n\n  /**\n   * Post SQ analysis overview on Stash\n   */\n  public void postAnalysisOverview(PullRequestRef pr,\n      Collection<PostJobIssue> issueReport,\n      StashClient stashClient) {\n\n    String report = getMarkdownPrinter().printReportMarkdown(issueReport);\n    stashClient.postCommentOnPullRequest(pr, report);\n\n    LOGGER.info(\"SonarQube analysis overview has been reported to Stash.\");\n  }\n\n  /**\n   * Approve pull-request\n   */\n  public void approvePullRequest(PullRequestRef pr, StashClient stashClient) {\n    stashClient.approvePullRequest(pr);\n\n    if (LOGGER.isDebugEnabled()) {\n      LOGGER.debug(\"Pull-request {} ({}/{}) APPROVED by user \\\"{}\\\"\",\n          pr.pullRequestId(), pr.project(), pr.repository(), stashClient.getLogin());\n    }\n  }\n\n  /**\n   * Reset pull-request approval\n   */\n  public void resetPullRequestApproval(PullRequestRef pr, StashClient stashClient) {\n    stashClient.resetPullRequestApproval(pr);\n\n    if (LOGGER.isDebugEnabled()) {\n      LOGGER.debug(\"Pull-request {} ({}/{}) NOT APPROVED by user \\\"{}\\\"\",\n          pr.pullRequestId(), pr.project(), pr.repository(), stashClient.getLogin());\n    }\n  }\n\n  /**\n   * Add a reviewer to the current pull-request.\n   */\n  public void addPullRequestReviewer(PullRequestRef pr, String userSlug, StashClient stashClient) {\n    StashPullRequest pullRequest = stashClient.getPullRequest(pr);\n\n    // user not yet in reviewer list\n    StashUser reviewer = pullRequest.getReviewer(userSlug);\n    if (reviewer == null) {\n      List<StashUser> reviewers = pullRequest.getReviewers();\n      reviewers.add(stashClient.getUser(userSlug));\n\n      stashClient.addPullRequestReviewer(pr, pullRequest.getVersion(), reviewers);\n\n      if (LOGGER.isDebugEnabled()) {\n        LOGGER.debug(\"User \\\"{}\\\" is now a reviewer of the pull-request #{} in {}/{}\",\n            userSlug, pr.pullRequestId(), pr.project(), pr.repository());\n      }\n    }\n  }\n\n  /**\n   * Push SonarQube report into the pull-request as comments.\n   */\n  public void postSonarQubeReport(PullRequestRef pr,\n      Iterable<PostJobIssue> issueReport,\n      StashDiffReport diffReport,\n      StashClient stashClient) {\n    postCommentPerIssue(pr, issueReport, diffReport, stashClient);\n    LOGGER.info(\"New SonarQube issues (if any) have been reported to Stash.\");\n  }\n\n  /**\n   * Post one comment by found issue on Stash.\n   */\n  void postCommentPerIssue(PullRequestRef pr, Iterable<PostJobIssue> issues,\n      StashDiffReport diffReport, StashClient stashClient) {\n\n    // to optimize request to Stash, builds comment match ordered by filepath\n    Map<String, StashCommentReport> commentsByFile = new HashMap<>();\n    for (PostJobIssue issue : issues) {\n      String path = getIssuePath(issue);\n      commentsByFile.computeIfAbsent(path, p -> {\n        StashCommentReport comments = stashClient.getPullRequestComments(pr, p);\n\n        // According to the type of the comment\n        // if type == CONTEXT, comment.line is set to source line instead of destination line\n        comments.applyDiffReport(diffReport);\n        return comments;\n      });\n    }\n\n    Severity issueSeverityThreshold = config.getIssueSeverityThreshold();\n    for (PostJobIssue issue : issues) {\n      if (issue.severity().compareTo(issueSeverityThreshold) >= 0) {\n        postIssueComment(pr, issue, commentsByFile, diffReport, stashClient, config.getTaskIssueSeverityThreshold());\n      }\n    }\n  }\n\n  private void postIssueComment(PullRequestRef pr,\n                                PostJobIssue issue,\n                                Map<String, StashCommentReport> commentsByFile,\n                                StashDiffReport diffReport,\n                                StashClient stashClient,\n                                Optional<Severity> taskSeverityThreshold\n  ) {\n\n    String issueKey = issue.key();\n    String path = getIssuePath(issue);\n    StashCommentReport comments = commentsByFile.get(path);\n    String commentContent = getMarkdownPrinter().printIssueMarkdown(issue);\n    Integer issueLine = issue.line();\n    if (issueLine == null) {\n      issueLine = 0;\n    }\n    // Surprisingly this syntax does not trigger the squid:NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE rule\n    //    but it does if you transform that into a ternary operator at the assignment level :/\n\n    // if comment not already pushed to Stash\n    if (comments != null && comments.contains(commentContent, path, issueLine)) {\n      LOGGER.debug(\"Comment \\\"{}\\\" already pushed on file {} ({})\", issueKey, path, issueLine);\n      return;\n    }\n\n    // check if issue belongs to the Stash diff view\n    IssueType type = diffReport.getType(path, issueLine, config.issueVicinityRange());\n    if (type == null) {\n      LOGGER.info(\n          \"Comment \\\"{}\\\" cannot be pushed to Stash like it does not belong to diff view - {} (line: {})\",\n          issueKey, path, issueLine);\n      return;\n    }\n\n    long line = diffReport.getLine(path, issueLine);\n\n    StashComment comment = stashClient\n        .postCommentLineOnPullRequest(pr, commentContent, path, line, type);\n\n    LOGGER\n        .info(\"Comment \\\"{}\\\" has been created ({}) on file {} ({})\", issueKey, type, path, line);\n\n    // Create task linked to the comment if configured\n\n    if (\n        taskSeverityThreshold.isPresent()\n        && issue.severity().compareTo(taskSeverityThreshold.get()) >= 0\n        ) {\n\n      stashClient.postTaskOnComment(issue.message(), comment.getId());\n\n      if (LOGGER.isDebugEnabled()) {\n        LOGGER.debug(\"Comment \\\"{}\\\" has been linked to a Stash task\", comment.getId());\n      }\n    }\n  }\n\n  public StashCredentials getCredentials() {\n    String passwordEnvVariable = config.getStashPasswordEnvironmentVariable();\n    String password = config.getStashPassword();\n    String userSlug = config.getStashUserSlug();\n\n    if (passwordEnvVariable != null) {\n      password = system.envVariable(passwordEnvVariable);\n      if (password == null) {\n        throw new StashConfigurationException(\n            \"Unable to retrieve password from configured environment variable \"\n                + StashPlugin.STASH_PASSWORD_ENVIRONMENT_VARIABLE);\n      }\n    }\n\n    if (userSlug == null) {\n      userSlug = config.getStashLogin();\n    }\n\n    return new StashCredentials(config.getStashLogin(), password, userSlug);\n  }\n\n  /**\n   * Mandatory Issue Threshold option.\n   *\n   * @throws StashConfigurationException if unable to get parameter as Integer\n   */\n  public int getIssueThreshold() {\n    int result = 0;\n    try {\n      result = config.getIssueThreshold();\n    } catch (NumberFormatException e) {\n      throw new StashConfigurationException(\"Unable to get \" + StashPlugin.STASH_ISSUE_THRESHOLD\n          + \" from plugin configuration\", e);\n    }\n    return result;\n  }\n\n  /**\n   * Mandatory Stash URL option.\n   *\n   * @throws StashConfigurationException if unable to get parameter\n   */\n  public String getStashURL() {\n    String result = config.getStashURL();\n    if (result == null) {\n      throw new StashConfigurationException(\n          MessageFormat.format(EXCEPTION_STASH_CONF, StashPlugin.STASH_URL));\n    }\n\n    if (result.endsWith(\"/\")) {\n      LOGGER.warn(\"Stripping trailing slash from {}, as it leads to invalid URLs\",\n          StashPlugin.STASH_URL);\n      result = StashPluginUtils.removeEnd(result, \"/\");\n    }\n\n    return result;\n  }\n\n  public PullRequestRef getPullRequest() {\n    return PullRequestRef.builder()\n        .setProject(getStashProject())\n        .setRepository(getStashRepository())\n        .setPullRequestId(getStashPullRequestId())\n        .build();\n  }\n\n  /**\n   * Mandatory Stash Project option.\n   *\n   * @throws StashConfigurationException if unable to get parameter\n   */\n  public String getStashProject() {\n    String result = config.getStashProject();\n    if (result == null) {\n      throw new StashConfigurationException(\n          MessageFormat.format(EXCEPTION_STASH_CONF, StashPlugin.STASH_PROJECT));\n    }\n\n    return result;\n  }\n\n  /**\n   * Mandatory Stash Repository option.\n   *\n   * @throws StashConfigurationException if unable to get parameter\n   */\n  public String getStashRepository() {\n    String result = config.getStashRepository();\n    if (result == null) {\n      throw new StashConfigurationException(\n          MessageFormat.format(EXCEPTION_STASH_CONF, StashPlugin.STASH_REPOSITORY));\n    }\n\n    return result;\n  }\n\n  /**\n   * Mandatory Stash pull-request ID option.\n   *\n   * @throws StashConfigurationException if unable to get parameter\n   */\n  public int getStashPullRequestId() {\n    Integer result = config.getPullRequestId();\n    if (result == null) {\n      throw new StashConfigurationException(MessageFormat.format(EXCEPTION_STASH_CONF,\n          StashPlugin.STASH_PULL_REQUEST_ID));\n    }\n\n    return result;\n  }\n\n  /**\n   * Get user who published the SQ analysis in Stash.\n   */\n  public StashUser getSonarQubeReviewer(String userSlug, StashClient stashClient) {\n    StashUser result = null;\n\n    result = stashClient.getUser(userSlug);\n\n    LOGGER.debug(\"SonarQube reviewer {} identified in Stash\", userSlug);\n    return result;\n  }\n\n  /**\n   * Get all changes exposed through the Stash pull-request.\n   */\n  public StashDiffReport getPullRequestDiffReport(PullRequestRef pr, StashClient stashClient) {\n    StashDiffReport result = stashClient.getPullRequestDiffs(pr);\n\n    if (LOGGER.isDebugEnabled()) {\n      LOGGER.debug(\"Stash differential report retrieved from pull request {} #{}\",\n          pr.repository(), pr.pullRequestId());\n    }\n\n    return result;\n  }\n\n  /**\n   * Reset all comments linked to a pull-request.\n   */\n  public void resetComments(PullRequestRef pr,\n      StashDiffReport diffReport,\n      StashUser sonarUser,\n      StashClient stashClient) {\n    // Let's call this \"diffRep_loop\"\n    for (StashComment comment : diffReport.getComments()) {\n\n      // delete comment only if published by the current SQ user\n      if (sonarUser.getId() != comment.getAuthor().getId()) {\n        continue;\n        // Next element in \"diffRep_loop\"\n\n        // comment contains tasks which cannot be deleted => do nothing\n      } else if (comment.containsPermanentTasks()) {\n        LOGGER.debug(\"Comment \\\"{}\\\" (path:\\\"{}\\\", line:\\\"{}\\\")\"\n                + \"CANNOT be deleted because one of its tasks is not deletable.\", comment.getId(),\n            comment.getPath(),\n            comment.getLine());\n        continue;  // Next element in \"diffRep_loop\"\n      }\n\n      // delete tasks linked to the current comment\n      for (StashTask task : comment.getTasks()) {\n        stashClient.deleteTaskOnComment(task);\n      }\n\n      stashClient.deletePullRequestComment(pr, comment);\n    }\n\n    LOGGER.info(\"SonarQube issues reported to Stash by user \\\"{}\\\" have been reset\",\n        sonarUser.getName());\n  }\n\n  @Override\n  public String getIssuePath(PostJobIssue issue) {\n    InputComponent ip = issue.inputComponent();\n    if (ip == null || !ip.isFile()) {\n      return null;\n    }\n    InputFile inputFile = (InputFile) ip;\n\n    Path baseDir = config\n        .getRepositoryRoot()\n        .orElse(projectBaseDir).toPath();\n\n\n    return new PathResolver().relativePath(baseDir, inputFile.path());\n  }\n}\n"
  },
  {
    "path": "src/main/java/org/sonar/plugins/stash/client/ContentType.java",
    "content": "package org.sonar.plugins.stash.client;\n\nimport static java.util.Objects.requireNonNull;\n\n/*\n * basic implementation of RFC 7231, section 3.1.1.1\n * subset of javax.mail.internet.ContentType\n */\npublic class ContentType {\n\n  private String primaryType;\n  private String subType;\n\n  public static final int CONTENTTYPE_ELEM_NUM = 2;\n\n  public ContentType(String primaryType, String subType, Object list) {\n    if (list != null) {\n      throw new IllegalArgumentException();\n    }\n    this.primaryType = requireNonNull(primaryType);\n    this.subType = requireNonNull(subType);\n  }\n\n  public boolean match(String s) {\n    String[] parts = s.split(\";\", CONTENTTYPE_ELEM_NUM);\n    // we ignore the parameters, match() does not care and we can't have our own\n    String[] types = parts[0].trim().split(\"/\", CONTENTTYPE_ELEM_NUM);\n    if (types.length < CONTENTTYPE_ELEM_NUM) {\n      return false;\n    }\n    \n    return primaryType.equalsIgnoreCase(types[0])\n           && subType.equalsIgnoreCase(types[1]);\n  }\n\n  @Override\n  public String toString() {\n    return primaryType + \"/\" + subType;\n  }\n}\n"
  },
  {
    "path": "src/main/java/org/sonar/plugins/stash/client/StashClient.java",
    "content": "package org.sonar.plugins.stash.client;\r\n\r\nimport com.github.cliftonlabs.json_simple.JsonArray;\r\nimport com.github.cliftonlabs.json_simple.JsonException;\r\nimport com.github.cliftonlabs.json_simple.JsonObject;\r\nimport com.github.cliftonlabs.json_simple.Jsoner;\r\nimport java.nio.charset.StandardCharsets;\r\nimport java.util.Optional;\r\nimport org.asynchttpclient.AsyncHttpClient;\r\nimport org.asynchttpclient.BoundRequestBuilder;\r\nimport org.asynchttpclient.DefaultAsyncHttpClient;\r\nimport org.asynchttpclient.DefaultAsyncHttpClientConfig;\r\nimport org.asynchttpclient.Realm;\r\nimport org.asynchttpclient.Request;\r\nimport org.asynchttpclient.Response;\r\nimport org.asynchttpclient.config.AsyncHttpClientConfigDefaults;\r\nimport org.sonar.api.utils.log.Logger;\r\nimport org.sonar.api.utils.log.Loggers;\r\nimport org.sonar.plugins.stash.PeekableInputStream;\r\nimport org.sonar.plugins.stash.PluginInfo;\r\nimport org.sonar.plugins.stash.PullRequestRef;\r\nimport org.sonar.plugins.stash.StashPlugin.IssueType;\r\nimport org.sonar.plugins.stash.StashPluginUtils;\r\nimport org.sonar.plugins.stash.exceptions.StashClientException;\r\nimport org.sonar.plugins.stash.issue.StashComment;\r\nimport org.sonar.plugins.stash.issue.StashCommentReport;\r\nimport org.sonar.plugins.stash.issue.StashDiffReport;\r\nimport org.sonar.plugins.stash.issue.StashPullRequest;\r\nimport org.sonar.plugins.stash.issue.StashTask;\r\nimport org.sonar.plugins.stash.issue.StashUser;\r\nimport org.sonar.plugins.stash.issue.collector.StashCollector;\r\n\r\nimport java.io.IOException;\r\nimport java.io.InputStreamReader;\r\nimport java.io.Reader;\r\nimport java.net.HttpURLConnection;\r\nimport java.text.MessageFormat;\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\nimport java.util.concurrent.ExecutionException;\r\nimport java.util.concurrent.TimeUnit;\r\nimport java.util.concurrent.TimeoutException;\r\n\r\npublic class StashClient implements AutoCloseable {\r\n  private static final Logger LOGGER = Loggers.get(StashClient.class);\r\n\r\n  private final String baseUrl;\r\n  private final StashCredentials credentials;\r\n  private final int stashTimeout;\r\n  private AsyncHttpClient httpClient;\r\n\r\n  private static final String REST_API = \"/rest/api/1.0/\";\r\n  private static final String USER_API = \"{0}\" + REST_API + \"users/{1}\";\r\n  private static final String REPO_API = \"{0}\" + REST_API + \"projects/{1}/repos/{2}/\";\r\n  private static final String TASKS_API = REST_API + \"tasks\";\r\n\r\n  private static final String API_ALL_PR = REPO_API + \"pull-requests/\";\r\n  private static final String API_ONE_PR = API_ALL_PR + \"{3,number,#}\";\r\n\r\n  private static final String API_ONE_PR_ALL_COMMENTS = API_ONE_PR + \"/comments\";\r\n  private static final String API_ONE_PR_DIFF = API_ONE_PR + \"/diff?withComments=true\";\r\n  private static final String API_ONE_PR_APPROVAL = API_ONE_PR + \"/approve\";\r\n  private static final String API_ONE_PR_COMMENT_PATH = API_ONE_PR + \"/comments?path={4}&start={5,number,#}\";\r\n\r\n  private static final String API_ONE_PR_ONE_COMMENT = API_ONE_PR_ALL_COMMENTS + \"/{4}?version={5}\";\r\n\r\n  private static final String PULL_REQUEST_APPROVAL_POST_ERROR_MESSAGE = \"Unable to change status of pull-request {0}\"\r\n                                                                       + \" #{1,number,#}.\";\r\n  private static final String PULL_REQUEST_GET_ERROR_MESSAGE = \"Unable to retrieve pull-request {0} #{1,number,#}.\";\r\n  private static final String PULL_REQUEST_PUT_ERROR_MESSAGE = \"Unable to update pull-request {0} #{1,number,#}.\";\r\n  private static final String USER_GET_ERROR_MESSAGE = \"Unable to retrieve user {0}.\";\r\n  private static final String COMMENT_POST_ERROR_MESSAGE = \"Unable to post a comment to {0} #{1,number,#}.\";\r\n  private static final String COMMENT_GET_ERROR_MESSAGE = \"Unable to get comment linked to {0} #{1,number,#}.\";\r\n  private static final String COMMENT_DELETION_ERROR_MESSAGE = \"Unable to delete comment {0,number,#}\"\r\n                                                             + \" from pull-request {1} #{2,number,#}.\";\r\n  private static final String TASK_POST_ERROR_MESSAGE = \"Unable to post a task on comment {0,number,#}.\";\r\n  private static final String TASK_DELETION_ERROR_MESSAGE = \"Unable to delete task {0,number,#}.\";\r\n\r\n  private static final ContentType JSON = new ContentType(\"application\", \"json\", null);\r\n\r\n  public StashClient(String url, StashCredentials credentials, int stashTimeout, String sonarQubeVersion) {\r\n    this.baseUrl = url;\r\n    this.credentials = credentials;\r\n    this.stashTimeout = stashTimeout;\r\n    this.httpClient = createHttpClient(sonarQubeVersion);\r\n  }\r\n\r\n  public String getBaseUrl() {\r\n    return baseUrl;\r\n  }\r\n\r\n  public String getLogin() {\r\n    return credentials.getLogin();\r\n  }\r\n\r\n  public void postCommentOnPullRequest(PullRequestRef pr, String report) {\r\n\r\n    String request = MessageFormat.format(API_ONE_PR_ALL_COMMENTS,\r\n                                          baseUrl,\r\n                                          pr.project(),\r\n                                          pr.repository(),\r\n                                          pr.pullRequestId());\r\n    JsonObject json = new JsonObject();\r\n    json.put(\"text\", report);\r\n\r\n    postCreate(request, json, MessageFormat.format(COMMENT_POST_ERROR_MESSAGE, pr.repository(), pr.pullRequestId()));\r\n  }\r\n\r\n  public StashCommentReport getPullRequestComments(PullRequestRef pr, String path) {\r\n    StashCommentReport result = new StashCommentReport();\r\n\r\n    long start = 0;\r\n    boolean isLastPage = false;\r\n\r\n    while (!isLastPage) {\r\n      String request = MessageFormat.format(API_ONE_PR_COMMENT_PATH,\r\n          baseUrl,\r\n          pr.project(),\r\n          pr.repository(),\r\n          pr.pullRequestId(),\r\n          path,\r\n          start);\r\n      JsonObject jsonComments = get(request,\r\n          MessageFormat.format(COMMENT_GET_ERROR_MESSAGE,\r\n              pr.repository(),\r\n              pr.pullRequestId()));\r\n      result.add(StashCollector.extractComments(jsonComments));\r\n\r\n      // Stash pagination: check if you get all comments linked to the pull-request\r\n      isLastPage = StashCollector.isLastPage(jsonComments);\r\n      start = StashCollector.getNextPageStart(jsonComments);\r\n    }\r\n\r\n    return result;\r\n  }\r\n\r\n  public void deletePullRequestComment(PullRequestRef pr, StashComment comment) {\r\n\r\n    String request = MessageFormat.format(API_ONE_PR_ONE_COMMENT,\r\n                                          baseUrl,\r\n                                          pr.project(),\r\n                                          pr.repository(),\r\n                                          pr.pullRequestId(),\r\n                                          Long.toString(comment.getId()),\r\n                                          Long.toString(comment.getVersion()));\r\n\r\n    delete(request,\r\n           MessageFormat.format(COMMENT_DELETION_ERROR_MESSAGE, comment.getId(), pr.repository(), pr.pullRequestId()));\r\n  }\r\n\r\n  public StashDiffReport getPullRequestDiffs(PullRequestRef pr) {\r\n    String request = MessageFormat.format(API_ONE_PR_DIFF,\r\n        baseUrl,\r\n        pr.project(),\r\n        pr.repository(),\r\n        pr.pullRequestId());\r\n    JsonObject jsonDiffs = get(request,\r\n        MessageFormat.format(COMMENT_GET_ERROR_MESSAGE, pr.repository(), pr.pullRequestId()));\r\n    return StashCollector.extractDiffs(jsonDiffs);\r\n  }\r\n\r\n  public StashComment postCommentLineOnPullRequest(PullRequestRef pr,\r\n                                                   String message,\r\n                                                   String path,\r\n                                                   long line,\r\n                                                   IssueType type) {\r\n    String request = MessageFormat.format(API_ONE_PR_ALL_COMMENTS,\r\n                                          baseUrl,\r\n                                          pr.project(),\r\n                                          pr.repository(),\r\n                                          pr.pullRequestId());\r\n\r\n    JsonObject anchor = new JsonObject();\r\n    if (line != 0L) {\r\n      anchor.put(\"line\", line);\r\n      anchor.put(\"lineType\", type.name());\r\n    }\r\n\r\n    String fileType = \"TO\";\r\n    if (type == IssueType.CONTEXT) {\r\n      fileType = \"FROM\";\r\n    }\r\n    anchor.put(\"fileType\", fileType);\r\n\r\n    anchor.put(\"path\", path);\r\n\r\n    JsonObject json = new JsonObject();\r\n    json.put(\"text\", message);\r\n    json.put(\"anchor\", anchor);\r\n\r\n    JsonObject response = postCreate(request, json,\r\n                                     MessageFormat.format(COMMENT_POST_ERROR_MESSAGE,\r\n                                                          pr.repository(),\r\n                                                          pr.pullRequestId()));\r\n\r\n    return StashCollector.extractComment(response, path, line);\r\n  }\r\n\r\n  public StashUser getUser(String userSlug) {\r\n\r\n    String request = MessageFormat.format(USER_API, baseUrl, userSlug);\r\n    JsonObject response = get(request, MessageFormat.format(USER_GET_ERROR_MESSAGE, userSlug));\r\n\r\n    return StashCollector.extractUser(response);\r\n  }\r\n\r\n  public StashPullRequest getPullRequest(PullRequestRef pr) {\r\n    String request = MessageFormat.format(API_ONE_PR, baseUrl, pr.project(), pr.repository(), pr.pullRequestId());\r\n    JsonObject response = get(request,\r\n                              MessageFormat.format(PULL_REQUEST_GET_ERROR_MESSAGE,\r\n                                                   pr.repository(),\r\n                                                   pr.pullRequestId()));\r\n\r\n    return StashCollector.extractPullRequest(pr, response);\r\n  }\r\n\r\n  public void addPullRequestReviewer(PullRequestRef pr, long pullRequestVersion, List<StashUser> reviewers) {\r\n    String request = MessageFormat.format(API_ONE_PR, baseUrl, pr.project(), pr.repository(), pr.pullRequestId());\r\n\r\n    JsonObject json = new JsonObject();\r\n\r\n    JsonArray jsonReviewers = new JsonArray();\r\n    for (StashUser reviewer : reviewers) {\r\n      JsonObject reviewerName = new JsonObject();\r\n      reviewerName.put(\"name\", reviewer.getName());\r\n\r\n      JsonObject user = new JsonObject();\r\n      user.put(\"user\", reviewerName);\r\n\r\n      jsonReviewers.add(user);\r\n    }\r\n\r\n    json.put(\"reviewers\", jsonReviewers);\r\n    json.put(\"id\", pr.pullRequestId());\r\n    json.put(\"version\", pullRequestVersion);\r\n\r\n    put(request, json, MessageFormat.format(PULL_REQUEST_PUT_ERROR_MESSAGE, pr.repository(), pr.pullRequestId()));\r\n  }\r\n\r\n  public void approvePullRequest(PullRequestRef pr) {\r\n    String request = MessageFormat.format(API_ONE_PR_APPROVAL,\r\n                                          baseUrl,\r\n                                          pr.project(),\r\n                                          pr.repository(),\r\n                                          pr.pullRequestId());\r\n    post(request,\r\n         null,\r\n         MessageFormat.format(PULL_REQUEST_APPROVAL_POST_ERROR_MESSAGE, pr.repository(), pr.pullRequestId()));\r\n  }\r\n\r\n  public void resetPullRequestApproval(PullRequestRef pr) {\r\n    String request = MessageFormat.format(API_ONE_PR_APPROVAL,\r\n                                          baseUrl,\r\n                                          pr.project(),\r\n                                          pr.repository(),\r\n                                          pr.pullRequestId());\r\n    delete(request,\r\n           HttpURLConnection.HTTP_OK,\r\n           MessageFormat.format(PULL_REQUEST_APPROVAL_POST_ERROR_MESSAGE, pr.repository(), pr.pullRequestId()));\r\n  }\r\n\r\n  public void postTaskOnComment(String message, Long commentId) {\r\n    String request = baseUrl + TASKS_API;\r\n\r\n    JsonObject anchor = new JsonObject();\r\n    anchor.put(\"id\", commentId);\r\n    anchor.put(\"type\", \"COMMENT\");\r\n\r\n    JsonObject json = new JsonObject();\r\n    json.put(\"anchor\", anchor);\r\n    json.put(\"text\", message);\r\n\r\n    postCreate(request, json, MessageFormat.format(TASK_POST_ERROR_MESSAGE, commentId));\r\n  }\r\n\r\n  public void deleteTaskOnComment(StashTask task) {\r\n    String request = baseUrl + TASKS_API + \"/\" + task.getId();\r\n    delete(request, MessageFormat.format(TASK_DELETION_ERROR_MESSAGE, task.getId()));\r\n  }\r\n\r\n  @Override\r\n  public void close() {\r\n    try {\r\n      httpClient.close();\r\n    } catch (IOException e) {\r\n      LOGGER.debug(\"Ignoring exception while closing StashClient: {}\", e, e);\r\n    }\r\n  }\r\n\r\n  private JsonObject get(String url, String errorMessage) {\r\n    return performRequest(httpClient.prepareGet(url), null, HttpURLConnection.HTTP_OK, errorMessage);\r\n  }\r\n\r\n  private JsonObject post(String url, JsonObject body, String errorMessage) {\r\n    return performRequest(httpClient.preparePost(url), body, HttpURLConnection.HTTP_OK, errorMessage);\r\n  }\r\n\r\n  private JsonObject postCreate(String url, JsonObject body, String errorMessage) {\r\n    return performRequest(httpClient.preparePost(url), body, HttpURLConnection.HTTP_CREATED, errorMessage);\r\n  }\r\n\r\n  private JsonObject delete(String url, int expectedStatusCode, String errorMessage) {\r\n    return performRequest(httpClient.prepareDelete(url), null, expectedStatusCode, errorMessage);\r\n  }\r\n\r\n  private JsonObject delete(String url, String errorMessage) {\r\n    return delete(url, HttpURLConnection.HTTP_NO_CONTENT, errorMessage);\r\n  }\r\n\r\n  private JsonObject put(String url, JsonObject body, String errorMessage) {\r\n    return performRequest(httpClient.preparePut(url), body, HttpURLConnection.HTTP_OK, errorMessage);\r\n  }\r\n\r\n  private void addAuth(BoundRequestBuilder requestBuilder) {\r\n    if (credentials != null && credentials.getLogin() != null) {\r\n      String password = Optional.ofNullable(credentials.getPassword()).orElse(\"\");\r\n      Realm realm = new Realm.Builder(credentials.getLogin(), password).setUsePreemptiveAuth(true)\r\n          .setScheme(Realm.AuthScheme.BASIC).build();\r\n      requestBuilder.setRealm(realm);\r\n    }\r\n  }\r\n\r\n  private JsonObject performRequest(BoundRequestBuilder requestBuilder,\r\n      JsonObject body,\r\n      int expectedStatusCode,\r\n      String errorMessage) {\r\n\r\n    if (body != null) {\r\n      requestBuilder.setBody(body.toJson());\r\n    }\r\n    addAuth(requestBuilder);\r\n    requestBuilder.setFollowRedirect(true);\r\n    requestBuilder.addHeader(\"Content-Type\", JSON.toString());\r\n    requestBuilder.addHeader(\"Accept\", JSON.toString());\r\n    requestBuilder.setCharset(StandardCharsets.UTF_8);\r\n\r\n    Request request = requestBuilder.build();\r\n\r\n    try {\r\n      Response response = httpClient.executeRequest(request).get(stashTimeout, TimeUnit.MILLISECONDS);\r\n      validateResponse(response, expectedStatusCode, errorMessage);\r\n      return extractResponse(response);\r\n\r\n    } catch (ExecutionException | TimeoutException e) {\r\n      throw new StashClientException(request.getUrl(), e);\r\n    } catch (InterruptedException e) {\r\n      Thread.currentThread().interrupt();\r\n      throw new StashClientException(request.getUrl(), e);\r\n    }\r\n  }\r\n\r\n  private static void validateResponse(Response response, int expectedStatusCode, String message) {\r\n\r\n    int responseCode = response.getStatusCode();\r\n    if (responseCode != expectedStatusCode) {\r\n      throw new StashClientException(message + \" Received \" + responseCode + \": \" + formatStashApiError(response));\r\n    }\r\n  }\r\n\r\n  private static JsonObject extractResponse(Response response) {\r\n    PeekableInputStream bodyStream = new PeekableInputStream(response.getResponseBodyAsStream());\r\n\r\n    try {\r\n      if (!bodyStream.peek().isPresent()) {\r\n        return null;\r\n      }\r\n      String contentType = response.getHeader(\"Content-Type\");\r\n      if (!JSON.match(contentType.trim())) {\r\n        throw new StashClientException(\"Received response with type \" + contentType + \" instead of JSON\");\r\n      }\r\n      Reader body = new InputStreamReader(bodyStream);\r\n      Object obj = Jsoner.deserialize(body);\r\n      return (JsonObject)obj;\r\n    } catch (JsonException | ClassCastException | IOException e) {\r\n      throw new StashClientException(\"Could not parse JSON response\", e);\r\n    }\r\n  }\r\n\r\n  private static String formatStashApiError(Response response) {\r\n\r\n    JsonObject responseJson = extractResponse(response);\r\n\r\n    // squid:S2259: making sure that we do not have a null value that would make a NullPointerException when used\r\n    if (responseJson == null) {\r\n      throw new StashClientException(\"The responseJson could not be extracted from the response !\");\r\n    }\r\n\r\n    JsonArray errors = (JsonArray)responseJson.get(\"errors\");\r\n\r\n    if (errors == null) {\r\n      throw new StashClientException(\"Error response did not contain an errors object '\" + responseJson + \"'\");\r\n    }\r\n\r\n    List<String> errorParts = new ArrayList<>();\r\n\r\n    for (Object o : errors) {\r\n      try {\r\n        JsonObject error = (JsonObject)o;\r\n        errorParts.add((String)error.get(\"exceptionName\") + \": \" + (String)error.get(\"message\"));\r\n      } catch (ClassCastException e) {\r\n        throw new StashClientException(\"Error response contained invalid error\", e);\r\n      }\r\n\r\n    }\r\n\r\n    return String.join(\", \", errorParts);\r\n  }\r\n\r\n  // We can't test this, as the manifest can only be loaded when deployed from a JAR-archive.\r\n  // During unit testing this is not the case\r\n  private static String getUserAgent(String sonarQubeVersion) {\r\n    PluginInfo info = StashPluginUtils.getPluginInfo();\r\n    String name;\r\n    String version;\r\n    name = version = \"unknown\";\r\n    if (info != null) {\r\n      name = info.getName();\r\n      version = info.getVersion();\r\n    }\r\n    return MessageFormat.format(\"SonarQube/{0} {1}/{2} {3}\",\r\n                                sonarQubeVersion == null ? \"unknown\" : sonarQubeVersion,\r\n                                name,\r\n                                version,\r\n                                AsyncHttpClientConfigDefaults.defaultUserAgent());\r\n  }\r\n\r\n  AsyncHttpClient createHttpClient(String sonarQubeVersion) {\r\n    return new DefaultAsyncHttpClient(\r\n        new DefaultAsyncHttpClientConfig.Builder()\r\n            .setUserAgent(getUserAgent(sonarQubeVersion))\r\n            .setCompressionEnforced(true)\r\n            .setUseProxySelector(true)\r\n            .setUseProxyProperties(true)\r\n            .build()\r\n    );\r\n  }\r\n}\r\n"
  },
  {
    "path": "src/main/java/org/sonar/plugins/stash/client/StashCredentials.java",
    "content": "package org.sonar.plugins.stash.client;\r\n\r\npublic class StashCredentials {\r\n\r\n  private final String login;\r\n  private final String password;\r\n  private final String userSlug;\r\n\r\n  public StashCredentials(String login, String password, String userSlug) {\r\n    this.login = login;\r\n    this.password = password;\r\n    this.userSlug = userSlug;\r\n  }\r\n\r\n  public String getLogin() {\r\n    return login;\r\n  }\r\n\r\n  public String getPassword() {\r\n    return password;\r\n  }\r\n\r\n  public String getUserSlug() {\r\n    return userSlug;\r\n  }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/org/sonar/plugins/stash/exceptions/StashClientException.java",
    "content": "package org.sonar.plugins.stash.exceptions;\r\n\r\npublic class StashClientException extends StashException {\r\n\r\n  private static final long serialVersionUID = -9071818008552452736L;\r\n\r\n  public StashClientException(String message) {\r\n    super(message);\r\n  }\r\n\r\n  public StashClientException(Throwable cause) {\r\n    super(cause);\r\n  }\r\n\r\n  public StashClientException(String message, Throwable cause) {\r\n    super(message, cause);\r\n  }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/org/sonar/plugins/stash/exceptions/StashConfigurationException.java",
    "content": "package org.sonar.plugins.stash.exceptions;\r\n\r\npublic class StashConfigurationException extends StashException {\r\n\r\n  private static final long serialVersionUID = 8423412434061160213L;\r\n\r\n  public StashConfigurationException(String message) {\r\n    super(message);\r\n  }\r\n\r\n  public StashConfigurationException(Throwable cause) {\r\n    super(cause);\r\n  }\r\n\r\n  public StashConfigurationException(String message, Throwable cause) {\r\n    super(message, cause);\r\n  }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/org/sonar/plugins/stash/exceptions/StashException.java",
    "content": "package org.sonar.plugins.stash.exceptions;\r\n\r\npublic class StashException extends RuntimeException {\r\n\r\n  private static final long serialVersionUID = -4529815924057418321L;\r\n\r\n  public StashException(String message) {\r\n    super(message);\r\n  }\r\n\r\n  public StashException(Throwable cause) {\r\n    super(cause);\r\n  }\r\n\r\n  public StashException(String message, Throwable cause) {\r\n    super(message, cause);\r\n  }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/org/sonar/plugins/stash/exceptions/StashReportExtractionException.java",
    "content": "package org.sonar.plugins.stash.exceptions;\r\n\r\npublic class StashReportExtractionException extends StashException {\r\n\r\n  private static final long serialVersionUID = -8105232303389875137L;\r\n\r\n  public StashReportExtractionException(String message) {\r\n    super(message);\r\n  }\r\n\r\n  public StashReportExtractionException(Throwable cause) {\r\n    super(cause);\r\n  }\r\n\r\n  public StashReportExtractionException(String message, Throwable cause) {\r\n    super(message, cause);\r\n  }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/org/sonar/plugins/stash/issue/MarkdownPrinter.java",
    "content": "package org.sonar.plugins.stash.issue;\r\n\r\nimport com.google.common.collect.ListMultimap;\r\nimport com.google.common.collect.Multimaps;\r\nimport java.util.ArrayList;\r\nimport java.util.Collection;\r\nimport java.util.Collections;\r\nimport java.util.Comparator;\r\nimport java.util.List;\r\nimport java.util.Map;\r\nimport java.util.Map.Entry;\r\nimport java.util.Arrays;\r\nimport java.util.function.Function;\r\nimport java.util.stream.Collectors;\r\n\r\nimport com.google.common.collect.ArrayListMultimap;\r\nimport org.sonar.api.batch.postjob.issue.PostJobIssue;\r\nimport org.sonar.api.batch.rule.Severity;\r\nimport org.sonar.api.rule.RuleKey;\r\nimport org.sonar.plugins.stash.IssuePathResolver;\r\n\r\nimport static org.sonar.plugins.stash.StashPluginUtils.countIssuesBySeverity;\r\n\r\npublic final class MarkdownPrinter {\r\n\r\n  private static final String NEW_LINE = \"\\n\";\r\n  private static final String CODING_RULES_RULE_KEY = \"coding_rules#rule_key=\";\r\n\r\n  private int issueThreshold;\r\n  private String sonarQubeURL;\r\n  private int includeFilesInOverview;\r\n  private IssuePathResolver issuePathResolver;\r\n\r\n  private Severity[] orderedSeverities;\r\n\r\n  public MarkdownPrinter(\r\n    int issueThreshold, String sonarQubeURL, int includeFilesInOverview, IssuePathResolver issuePathResolver\r\n  ) {\r\n    this.issueThreshold = issueThreshold;\r\n    this.sonarQubeURL = sonarQubeURL;\r\n    this.includeFilesInOverview = includeFilesInOverview;\r\n    this.issuePathResolver = issuePathResolver;\r\n\r\n    orderedSeverities = Severity.values();\r\n    Arrays.sort(orderedSeverities, Comparator.reverseOrder());\r\n  }\r\n\r\n  public static String printSeverityMarkdown(org.sonar.api.batch.rule.Severity severity) {\r\n    StringBuilder sb = new StringBuilder();\r\n    sb.append(\"*\").append(severity.name().toUpperCase()).append(\"*\").append(\" - \");\r\n\r\n    return sb.toString();\r\n  }\r\n\r\n  public static String printIssueNumberBySeverityMarkdown(Collection<PostJobIssue> report, Severity severity) {\r\n    StringBuilder sb = new StringBuilder();\r\n    long issueNumber = countIssuesBySeverity(report, severity);\r\n    sb.append(\"| \").append(severity).append(\" | \").append(issueNumber).append(\" |\")\r\n        .append(NEW_LINE);\r\n\r\n    return sb.toString();\r\n  }\r\n\r\n  public String printIssueMarkdown(PostJobIssue issue) {\r\n    StringBuilder sb = new StringBuilder();\r\n    String message = issue.message();\r\n\r\n    if (message == null) {\r\n      return \"No message\";\r\n    }\r\n\r\n    sb.append(MarkdownPrinter.printSeverityMarkdown(issue.severity()))\r\n        .append(message)\r\n        .append(\" [\")\r\n        .append(link(issue.ruleKey().toString(),\r\n            sonarQubeURL + \"/\" + CODING_RULES_RULE_KEY + issue.ruleKey()))\r\n        .append(\"]\");\r\n\r\n    return sb.toString();\r\n  }\r\n\r\n  public String printReportMarkdown(Collection<PostJobIssue> allIssues) {\r\n    StringBuilder sb = new StringBuilder(\"## SonarQube analysis Overview\");\r\n    sb.append(NEW_LINE);\r\n\r\n    if (allIssues.isEmpty()) {\r\n\r\n      sb.append(\"### No new issues detected!\");\r\n      sb.append(NEW_LINE).append(NEW_LINE);\r\n\r\n    } else {\r\n\r\n      int issueNumber = allIssues.size();\r\n\r\n      if (issueNumber >= issueThreshold) {\r\n        sb.append(\"### Too many issues detected \");\r\n        sb.append(\"(\").append(issueNumber).append(\"/\").append(issueThreshold).append(\")\");\r\n        sb.append(\": Issues cannot be displayed in Diff view.\").append(NEW_LINE).append(NEW_LINE);\r\n      }\r\n\r\n      sb.append(\"| Total New Issues | \").append(issueNumber).append(\" |\").append(NEW_LINE);\r\n      sb.append(\"|-----------------|------|\").append(NEW_LINE);\r\n      for (Severity severity : orderedSeverities) {\r\n        sb.append(printIssueNumberBySeverityMarkdown(allIssues, severity));\r\n      }\r\n\r\n      ListMultimap<RuleKey, PostJobIssue> uniqueInformation = allIssues.stream().collect(Multimaps.toMultimap(PostJobIssue::ruleKey, Function.identity(), ArrayListMultimap::create));\r\n\r\n      List<Map.Entry<RuleKey, List<PostJobIssue>>> uniqueSortedInformation = Multimaps.asMap(uniqueInformation)\r\n              .entrySet().stream()\r\n              .sorted(bySeverity.reversed())\r\n              .collect(Collectors.toList());\r\n      sb.append(\r\n          formatTableList(uniqueSortedInformation));\r\n    }\r\n\r\n    return sb.toString();\r\n  }\r\n\r\n  private String formatTableList(List<Map.Entry<RuleKey, List<PostJobIssue>>> items) {\r\n    if (items.isEmpty()) {\r\n      return \"\";\r\n    }\r\n\r\n    String caption = \"Issues list\";\r\n    StringBuilder sb = new StringBuilder();\r\n    sb.append(NEW_LINE).append(NEW_LINE);\r\n    sb.append(\"| \").append(caption).append(\" |\").append(NEW_LINE);\r\n    sb.append(\"|\");\r\n    sb.append(repeatString(caption.length() + 2, \"-\"));\r\n    sb.append(\"|\");\r\n    sb.append(NEW_LINE);\r\n    for (Map.Entry<RuleKey, List<PostJobIssue>> item : items) {\r\n      List<PostJobIssue> issues = item.getValue();\r\n      sb.append(\"| \").append(printIssueMarkdown(issues.get(0))).append(\" |\").append(NEW_LINE);\r\n        if (this.includeFilesInOverview > 0) {\r\n            sb.append(\"| &nbsp;&nbsp; *Files: \").append(fileNameList(issues)).append(\"* |\").append(NEW_LINE);\r\n        }\r\n    }\r\n\r\n    return sb.toString();\r\n  }\r\n\r\n  private String fileNameList(List<PostJobIssue> issues) {\r\n    List<String> names = new ArrayList<>();\r\n\r\n    issues.sort(issueFormatComparator);\r\n\r\n    for (PostJobIssue issue: issues.subList(0, Math.min(includeFilesInOverview, issues.size()))) {\r\n      String path = issuePathResolver.getIssuePath(issue);\r\n      Integer line = issue.line();\r\n      if (line == null) {\r\n        names.add(path);\r\n      } else {\r\n        names.add(String.format(\"%s:%s\", path, line));\r\n      }\r\n    }\r\n    if (issues.size() > includeFilesInOverview) {\r\n      names.add(\"...\");\r\n    }\r\n    return String.join(\", \", names);\r\n  }\r\n\r\n  private String repeatString(int n, String s) {\r\n    return String.join(\"\", Collections.nCopies(n, s));\r\n  }\r\n\r\n  private static String link(String title, String target) {\r\n    return \"[\" + title + \"](\" + target + \")\";\r\n  }\r\n\r\n  private static Comparator<? super Entry<RuleKey, ? extends Collection<PostJobIssue>>> bySeverity = Comparator.comparing(\r\n      // List invariant is guaranteed by docs\r\n      e -> ((List<PostJobIssue>) e.getValue()).get(0).severity());\r\n\r\n  private Comparator<PostJobIssue> fileNameLength = Comparator\r\n      .comparing(i -> issuePathResolver.getIssuePath(i).length());\r\n\r\n  private Comparator<PostJobIssue> issueLine = Comparator\r\n      // -1 sorts before all issues with lines\r\n      .comparing(issue -> firstNonNull(issue.line(), -1));\r\n\r\n  private Comparator<PostJobIssue> fileNameLexical = Comparator\r\n      .comparing(i -> issuePathResolver.getIssuePath(i));\r\n\r\n  private Comparator<PostJobIssue> issueFormatComparator =\r\n      fileNameLength\r\n      .thenComparing(issueLine)\r\n      .thenComparing(fileNameLexical)\r\n      ;\r\n\r\n  @SafeVarargs\r\n  private static <T> T firstNonNull(T... args) {\r\n    for (T t: args) {\r\n      if (t != null) {\r\n        return t;\r\n      }\r\n    }\r\n    throw new IllegalStateException(\"At least one of the arguments should have been non-null\");\r\n  }\r\n}\r\n"
  },
  {
    "path": "src/main/java/org/sonar/plugins/stash/issue/StashComment.java",
    "content": "package org.sonar.plugins.stash.issue;\r\n\r\nimport com.google.common.base.MoreObjects;\r\nimport java.util.ArrayList;\r\nimport java.util.Collections;\r\nimport java.util.List;\r\n\r\n\r\npublic class StashComment {\r\n\r\n  private final long id;\r\n  private final String message;\r\n  private final StashUser author;\r\n  private final long version;\r\n  private long line;\r\n  private String path;\r\n  private List<StashTask> tasks;\r\n\r\n  public StashComment(long id, String message, String path, Long line, StashUser author, long version) {\r\n    this.id = id;\r\n    this.message = message;\r\n    this.path = path;\r\n    this.author = author;\r\n    this.version = version;\r\n\r\n    // Stash comment can be null if comment is global to all the file\r\n    if (line == null) {\r\n      this.line = 0;\r\n    } else {\r\n      this.line = line.longValue();\r\n    }\r\n\r\n    tasks = new ArrayList<>();\r\n  }\r\n\r\n  public long getId() {\r\n    return id;\r\n  }\r\n\r\n  public void setLine(long line) {\r\n    this.line = line;\r\n  }\r\n\r\n  public void setPath(String path) {\r\n    this.path = path;\r\n  }\r\n\r\n  public String getMessage() {\r\n    return message;\r\n  }\r\n\r\n  public String getPath() {\r\n    return path;\r\n  }\r\n\r\n  public long getLine() {\r\n    return line;\r\n  }\r\n\r\n  public StashUser getAuthor() {\r\n    return author;\r\n  }\r\n\r\n  public long getVersion() {\r\n    return version;\r\n  }\r\n\r\n  public List<StashTask> getTasks() {\r\n    return Collections.unmodifiableList(tasks);\r\n  }\r\n\r\n  public void addTask(StashTask task) {\r\n    tasks.add(task);\r\n  }\r\n\r\n  public boolean containsPermanentTasks() {\r\n    boolean result = false;\r\n\r\n    for (StashTask task : tasks) {\r\n      if (!task.isDeletable()) {\r\n        result = true;\r\n        break;\r\n      }\r\n    }\r\n\r\n    return result;\r\n  }\r\n\r\n  @Override\r\n  public boolean equals(Object object) {\r\n    boolean result = false;\r\n    if (object instanceof StashComment) {\r\n      StashComment stashComment = (StashComment)object;\r\n      result = this.getId() == stashComment.getId();\r\n    }\r\n\r\n    return result;\r\n  }\r\n\r\n  @Override\r\n  public int hashCode() {\r\n    return (int)this.getId();\r\n  }\r\n\r\n  @Override\r\n  public String toString() {\r\n    return MoreObjects.toStringHelper(this)\r\n        .add(\"id\", id)\r\n        .add(\"message\", message)\r\n        .add(\"author\", author)\r\n        .add(\"version\", version)\r\n        .add(\"line\", line)\r\n        .add(\"path\", path)\r\n        .add(\"tasks\", tasks)\r\n        .toString();\r\n  }\r\n}\r\n"
  },
  {
    "path": "src/main/java/org/sonar/plugins/stash/issue/StashCommentReport.java",
    "content": "package org.sonar.plugins.stash.issue;\r\n\r\nimport java.util.Objects;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\nimport org.sonar.api.utils.log.Logger;\r\nimport org.sonar.api.utils.log.Loggers;\r\nimport org.sonar.plugins.stash.StashPlugin.IssueType;\r\n\r\npublic class StashCommentReport {\r\n\r\n  private static final Logger LOGGER = Loggers.get(StashCommentReport.class);\r\n\r\n  private List<StashComment> comments;\r\n\r\n  public StashCommentReport() {\r\n    this.comments = new ArrayList<>();\r\n  }\r\n\r\n  public List<StashComment> getComments() {\r\n    return comments;\r\n  }\r\n\r\n  public void add(StashComment comment) {\r\n    comments.add(comment);\r\n  }\r\n\r\n  public void add(StashCommentReport report) {\r\n    for (StashComment comment : report.getComments()) {\r\n      comments.add(comment);\r\n    }\r\n  }\r\n\r\n  public boolean contains(String message, String path, long line) {\r\n    boolean result = false;\r\n    for (StashComment comment : comments) {\r\n\r\n      if (Objects.equals(comment.getMessage(), message)\r\n       && Objects.equals(comment.getPath(), path)\r\n       && comment.getLine() == line) {\r\n\r\n        result = true;\r\n        break;\r\n      }\r\n    }\r\n\r\n    return result;\r\n  }\r\n\r\n  public StashCommentReport applyDiffReport(StashDiffReport diffReport) {\r\n    for (StashComment comment : comments) {\r\n      StashDiff diff = diffReport.getDiffByComment(comment.getId());\r\n      if ((diff != null) && diff.getType() == IssueType.CONTEXT) {\r\n\r\n        // By default comment line, with type == CONTEXT, is set to FROM value.\r\n        // Set comment line to TO value to be compared with SonarQube issue.\r\n        long destination = diff.getDestination();\r\n        comment.setLine(destination);\r\n\r\n        LOGGER.debug(\"Update Stash comment \\\"{}\\\": set comment line to destination diff line ({})\",\r\n                     comment.getId(),\r\n                     comment.getLine());\r\n      }\r\n    }\r\n\r\n    return this;\r\n  }\r\n\r\n  public int size() {\r\n    return comments.size();\r\n  }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/org/sonar/plugins/stash/issue/StashDiff.java",
    "content": "package org.sonar.plugins.stash.issue;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.Collections;\r\nimport java.util.List;\r\nimport org.sonar.plugins.stash.StashPlugin.IssueType;\r\n\r\npublic class StashDiff {\r\n\r\n  private final IssueType type;\r\n  private final String path;\r\n  private final long source;\r\n  private final long destination;\r\n  private final List<StashComment> comments;\r\n\r\n  public StashDiff(IssueType type, String path, long source, long destination) {\r\n    this.type = type;\r\n    this.path = path;\r\n    this.source = source;\r\n    this.destination = destination;\r\n    this.comments = new ArrayList<>();\r\n  }\r\n\r\n  public void addComment(StashComment comment) {\r\n    this.comments.add(comment);\r\n  }\r\n\r\n  public String getPath() {\r\n    return path;\r\n  }\r\n\r\n  public long getSource() {\r\n    return source;\r\n  }\r\n\r\n  public long getDestination() {\r\n    return destination;\r\n  }\r\n\r\n  public IssueType getType() {\r\n    return type;\r\n  }\r\n\r\n  public List<StashComment> getComments() {\r\n    return Collections.unmodifiableList(comments);\r\n  }\r\n\r\n  public boolean containsComment(long commentId) {\r\n    return comments.stream().anyMatch(c -> c.getId() == commentId);\r\n  }\r\n}\r\n"
  },
  {
    "path": "src/main/java/org/sonar/plugins/stash/issue/StashDiffReport.java",
    "content": "package org.sonar.plugins.stash.issue;\r\n\r\nimport com.google.common.collect.Range;\r\nimport java.util.Collections;\r\nimport java.util.Objects;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\nimport org.sonar.plugins.stash.StashPlugin.IssueType;\r\n\r\n/**\r\n * This class is a representation of the Stash Diff view.\r\n * <p>\r\n * Purpose is to check if a SonarQube issue belongs to the Stash diff view before posting.\r\n * Indeed, Stash Diff view displays only comments which belong to this view.\r\n */\r\npublic class StashDiffReport {\r\n\r\n  public static final int VICINITY_RANGE_NONE = 0;\r\n\r\n  private List<StashDiff> diffs;\r\n\r\n  public StashDiffReport() {\r\n    this.diffs = new ArrayList<>();\r\n  }\r\n\r\n  public List<StashDiff> getDiffs() {\r\n    return Collections.unmodifiableList(diffs);\r\n  }\r\n\r\n  public void add(StashDiff diff) {\r\n    diffs.add(diff);\r\n  }\r\n\r\n  public void add(StashDiffReport report) {\r\n    diffs.addAll(report.getDiffs());\r\n  }\r\n\r\n  private static boolean inVicinityOfChangedDiff(StashDiff diff, long destination, int range) {\r\n    if (range <= 0) {\r\n      return false;\r\n    }\r\n    long lower = Math.min(diff.getSource(), diff.getDestination());\r\n    long upper = Math.max(diff.getSource(), diff.getDestination());\r\n    return Range.closed(lower - range, upper + range).contains(destination);\r\n  }\r\n\r\n  private static boolean isChangedDiff(StashDiff diff, long destination) {\r\n    return diff.getDestination() == destination;\r\n  }\r\n\r\n  private static boolean lineIsChangedDiff(StashDiff diff) {\r\n    return !diff.getType().equals(IssueType.CONTEXT);\r\n  }\r\n\r\n  public IssueType getType(String path, long destination, int vicinityRange) {\r\n    boolean isInContextDiff = false;\r\n    for (StashDiff diff : diffs) {\r\n      if (Objects.equals(diff.getPath(), path)) {\r\n        // Line 0 never belongs to Stash Diff view.\r\n        // It is a global comment with a type set to CONTEXT.\r\n        if (destination == 0) {\r\n          return IssueType.CONTEXT;\r\n        } else if (!lineIsChangedDiff(diff)) {\r\n          // We only care about changed diff\r\n          continue;\r\n        } else if (isChangedDiff(diff, destination)) {\r\n          return diff.getType();\r\n        } else if (inVicinityOfChangedDiff(diff, destination, vicinityRange)) {\r\n          isInContextDiff = true;\r\n        }\r\n      }\r\n    }\r\n    return isInContextDiff ? IssueType.CONTEXT : null;\r\n  }\r\n\r\n  /**\r\n   * Depends on the type of the diff.\r\n   * If type == \"CONTEXT\", return the source line of the diff.\r\n   * If type == \"ADDED\", return the destination line of the diff.\r\n   */\r\n  public long getLine(String path, long destination) {\r\n    for (StashDiff diff : diffs) {\r\n      if (Objects.equals(diff.getPath(), path) && (diff.getDestination() == destination)) {\r\n\r\n        if (diff.getType() == IssueType.CONTEXT) {\r\n          return diff.getSource();\r\n        } else {\r\n          return diff.getDestination();\r\n        }\r\n      }\r\n    }\r\n    return 0;\r\n  }\r\n\r\n  public StashDiff getDiffByComment(long commentId) {\r\n    for (StashDiff diff : diffs) {\r\n      if (diff.containsComment(commentId)) {\r\n        return diff;\r\n      }\r\n    }\r\n    return null;\r\n  }\r\n\r\n  /**\r\n   * Get all comments from the Stash differential report.\r\n   */\r\n  public List<StashComment> getComments() {\r\n    List<StashComment> result = new ArrayList<>();\r\n\r\n    for (StashDiff diff : this.diffs) {\r\n      List<StashComment> comments = diff.getComments();\r\n\r\n      for (StashComment comment : comments) {\r\n        if (!result.contains(comment)) {\r\n          result.add(comment);\r\n        }\r\n      }\r\n    }\r\n    return result;\r\n  }\r\n}\r\n"
  },
  {
    "path": "src/main/java/org/sonar/plugins/stash/issue/StashPullRequest.java",
    "content": "package org.sonar.plugins.stash.issue;\r\n\r\nimport org.sonar.plugins.stash.PullRequestRef;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\n\r\npublic class StashPullRequest {\r\n\r\n  private final PullRequestRef ref;\r\n\r\n  private long version;\r\n\r\n  private final ArrayList<StashUser> reviewers;\r\n\r\n  public int getId() {\r\n    return ref.pullRequestId();\r\n  }\r\n\r\n  public String getProject() {\r\n    return ref.project();\r\n  }\r\n\r\n  public String getRepository() {\r\n    return ref.repository();\r\n  }\r\n\r\n  public StashPullRequest(PullRequestRef pr) {\r\n    this.ref = pr;\r\n\r\n    this.reviewers = new ArrayList<>();\r\n  }\r\n\r\n  public PullRequestRef getRef() {\r\n    return ref;\r\n  }\r\n\r\n  public long getVersion() {\r\n    return version;\r\n  }\r\n\r\n  public void setVersion(long version) {\r\n    this.version = version;\r\n  }\r\n\r\n  public void addReviewer(StashUser reviewer) {\r\n    this.reviewers.add(reviewer);\r\n  }\r\n\r\n  public List<StashUser> getReviewers() {\r\n    return reviewers;\r\n  }\r\n\r\n  public StashUser getReviewer(String user) {\r\n    StashUser result = null;\r\n    for (StashUser stashReviewer : reviewers) {\r\n      if (user.equals(stashReviewer.getSlug())) {\r\n        result = stashReviewer;\r\n        break;\r\n      }\r\n    }\r\n\r\n    return result;\r\n  }\r\n\r\n  public boolean containsReviewer(StashUser reviewer) {\r\n    boolean result = false;\r\n    for (StashUser stashReviewer : reviewers) {\r\n      if (reviewer.getId() == stashReviewer.getId()) {\r\n        result = true;\r\n        break;\r\n      }\r\n    }\r\n\r\n    return result;\r\n  }\r\n}\r\n"
  },
  {
    "path": "src/main/java/org/sonar/plugins/stash/issue/StashTask.java",
    "content": "package org.sonar.plugins.stash.issue;\r\n\r\npublic class StashTask {\r\n\r\n  private final Long id;\r\n  private final String text;\r\n  private final String state;\r\n  private final boolean deletable;\r\n\r\n  public StashTask(Long id, String text, String state, boolean deletable) {\r\n    this.id = id;\r\n    this.text = text;\r\n    this.state = state;\r\n    this.deletable = deletable;\r\n  }\r\n\r\n  public Long getId() {\r\n    return id;\r\n  }\r\n\r\n  public String getText() {\r\n    return text;\r\n  }\r\n\r\n  public String getState() {\r\n    return state;\r\n  }\r\n\r\n  public boolean isDeletable() {\r\n    return deletable;\r\n  }\r\n}\r\n"
  },
  {
    "path": "src/main/java/org/sonar/plugins/stash/issue/StashUser.java",
    "content": "package org.sonar.plugins.stash.issue;\r\n\r\npublic class StashUser {\r\n\r\n  private final long id;\r\n  private final String name;\r\n  private final String slug;\r\n  private final String email;\r\n\r\n  public StashUser(long id, String name, String slug, String email) {\r\n    this.id = id;\r\n    this.name = name;\r\n    this.slug = slug;\r\n    this.email = email;\r\n  }\r\n\r\n  public long getId() {\r\n    return id;\r\n  }\r\n\r\n  public String getName() {\r\n    return name;\r\n  }\r\n\r\n  public String getSlug() {\r\n    return slug;\r\n  }\r\n\r\n  public String getEmail() {\r\n    return email;\r\n  }\r\n}\r\n"
  },
  {
    "path": "src/main/java/org/sonar/plugins/stash/issue/collector/SonarQubeCollector.java",
    "content": "package org.sonar.plugins.stash.issue.collector;\r\n\r\nimport java.util.Set;\r\n\r\nimport static org.sonar.plugins.stash.StashPluginUtils.isProjectWide;\r\n\r\nimport java.util.List;\r\nimport java.util.stream.Collectors;\r\nimport java.util.stream.StreamSupport;\r\nimport org.sonar.api.batch.postjob.issue.PostJobIssue;\r\nimport org.sonar.api.rule.RuleKey;\r\nimport org.sonar.api.utils.log.Logger;\r\nimport org.sonar.api.utils.log.Loggers;\r\nimport org.sonar.plugins.stash.IssuePathResolver;\r\n\r\npublic final class SonarQubeCollector {\r\n\r\n  private static final Logger LOGGER = Loggers.get(SonarQubeCollector.class);\r\n\r\n  private SonarQubeCollector() {\r\n    // Hiding implicit public constructor with an explicit private one (squid:S1118)\r\n  }\r\n\r\n  /**\r\n   * Create issue report according to issue list generated during SonarQube\r\n   * analysis.\r\n   */\r\n  public static List<PostJobIssue> extractIssueReport(\r\n      Iterable<PostJobIssue> issues, IssuePathResolver issuePathResolver,\r\n      boolean includeExistingIssues, Set<RuleKey> excludedRules) {\r\n    return StreamSupport.stream(\r\n        issues.spliterator(), false)\r\n                        .filter(issue -> shouldIncludeIssue(\r\n                            issue, issuePathResolver,\r\n                            includeExistingIssues, excludedRules\r\n                        ))\r\n                        .collect(Collectors.toList());\r\n  }\r\n\r\n  static boolean shouldIncludeIssue(\r\n      PostJobIssue issue, IssuePathResolver issuePathResolver,\r\n      boolean includeExistingIssues, Set<RuleKey> excludedRules\r\n  ) {\r\n    if (!includeExistingIssues && !issue.isNew()) {\r\n      if (LOGGER.isDebugEnabled()) {\r\n        LOGGER.debug(\"Issue {} is not a new issue and so, not added to the report\", issue.key());\r\n      }\r\n      return false;\r\n    }\r\n\r\n    if (excludedRules.contains(issue.ruleKey())) {\r\n      if (LOGGER.isDebugEnabled()) {\r\n        LOGGER.debug(\"Issue {} is ignored, not added to the report\", issue.key());\r\n      }\r\n      return false;\r\n    }\r\n\r\n    String path = issuePathResolver.getIssuePath(issue);\r\n    if (!isProjectWide(issue) && path == null) {\r\n      if (LOGGER.isDebugEnabled()) {\r\n        LOGGER.debug(\"Issue {} is not linked to a file, not added to the report\", issue.key());\r\n      }\r\n      return false;\r\n    }\r\n    return true;\r\n  }\r\n}\r\n"
  },
  {
    "path": "src/main/java/org/sonar/plugins/stash/issue/collector/StashCollector.java",
    "content": "package org.sonar.plugins.stash.issue.collector;\r\n\r\nimport com.github.cliftonlabs.json_simple.JsonArray;\r\nimport com.github.cliftonlabs.json_simple.JsonObject;\r\nimport java.math.BigDecimal;\r\nimport org.sonar.plugins.stash.PullRequestRef;\r\nimport org.sonar.plugins.stash.StashPlugin.IssueType;\r\nimport org.sonar.plugins.stash.exceptions.StashReportExtractionException;\r\nimport org.sonar.plugins.stash.issue.StashComment;\r\nimport org.sonar.plugins.stash.issue.StashCommentReport;\r\nimport org.sonar.plugins.stash.issue.StashDiff;\r\nimport org.sonar.plugins.stash.issue.StashDiffReport;\r\nimport org.sonar.plugins.stash.issue.StashPullRequest;\r\nimport org.sonar.plugins.stash.issue.StashTask;\r\nimport org.sonar.plugins.stash.issue.StashUser;\r\n\r\npublic final class StashCollector {\r\n\r\n  private static final String AUTHOR = \"author\";\r\n  private static final String VERSION = \"version\";\r\n\r\n  private StashCollector() {\r\n    // Hiding implicit public constructor with an explicit private one (squid:S1118)\r\n  }\r\n\r\n  public static StashCommentReport extractComments(JsonObject jsonComments) {\r\n    StashCommentReport result = new StashCommentReport();\r\n\r\n    JsonArray jsonValues = (JsonArray)jsonComments.get(\"values\");\r\n    if (jsonValues != null) {\r\n\r\n      for (Object obj : jsonValues.toArray()) {\r\n        JsonObject jsonComment = (JsonObject)obj;\r\n\r\n        StashComment comment = extractComment(jsonComment);\r\n        result.add(comment);\r\n      }\r\n    }\r\n\r\n    return result;\r\n  }\r\n\r\n  public static StashComment extractComment(JsonObject jsonComment, String path, Long line) {\r\n\r\n    long id = getLong(jsonComment, \"id\");\r\n    String message = (String)jsonComment.get(\"text\");\r\n\r\n    long version = getLong(jsonComment, VERSION);\r\n\r\n    JsonObject jsonAuthor = (JsonObject)jsonComment.get(AUTHOR);\r\n    StashUser stashUser = extractUser(jsonAuthor);\r\n\r\n    return new StashComment(id, message, path, line, stashUser, version);\r\n  }\r\n\r\n  public static StashComment extractComment(JsonObject jsonComment) {\r\n\r\n    JsonObject jsonAnchor = (JsonObject)jsonComment.get(\"anchor\");\r\n    if (jsonAnchor == null) {\r\n      throw new StashReportExtractionException(\"JSON Comment does not contain any \\\"anchor\\\" tag\"\r\n                                               + \" to describe comment \\\"line\\\" and \\\"path\\\"\");\r\n    }\r\n\r\n    String path = (String)jsonAnchor.get(\"path\");\r\n\r\n    // can be null if comment is attached to the global file\r\n    Long line = getLong(jsonAnchor, \"line\");\r\n\r\n    return extractComment(jsonComment, path, line);\r\n  }\r\n\r\n  public static StashPullRequest extractPullRequest(PullRequestRef pr,\r\n                                                    JsonObject jsonPullRequest) {\r\n    StashPullRequest result = new StashPullRequest(pr);\r\n\r\n    long version = getLong(jsonPullRequest, VERSION);\r\n    result.setVersion(version);\r\n\r\n    JsonArray jsonReviewers = (JsonArray)jsonPullRequest.get(\"reviewers\");\r\n    if (jsonReviewers != null) {\r\n      for (Object objReviewer : jsonReviewers.toArray()) {\r\n        JsonObject jsonReviewer = (JsonObject)objReviewer;\r\n\r\n        JsonObject jsonUser = (JsonObject)jsonReviewer.get(\"user\");\r\n        if (jsonUser != null) {\r\n          StashUser reviewer = extractUser(jsonUser);\r\n          result.addReviewer(reviewer);\r\n        }\r\n      }\r\n    }\r\n\r\n    return result;\r\n  }\r\n\r\n  public static StashUser extractUser(JsonObject jsonUser) {\r\n    long id = getLong(jsonUser, \"id\");\r\n    String name = (String)jsonUser.get(\"name\");\r\n    String slug = (String)jsonUser.get(\"slug\");\r\n    String email = (String)jsonUser.get(\"email\");\r\n\r\n    return new StashUser(id, name, slug, email);\r\n  }\r\n\r\n  public static StashDiffReport extractDiffs(JsonObject jsonObject) {\r\n\r\n    StashDiffReport result = new StashDiffReport();\r\n    JsonArray jsonDiffs = (JsonArray)jsonObject.get(\"diffs\");\r\n\r\n    if (jsonDiffs == null) {\r\n      return null;\r\n    }\r\n\r\n    // Let's call this for loop \"objdiff_loop\"\r\n    for (Object objDiff : jsonDiffs.toArray()) {\r\n\r\n      JsonObject jsonDiff = (JsonObject)objDiff;\r\n      // destination path in diff view\r\n      // if status of the file is deleted, destination == null\r\n      JsonObject destinationPath = (JsonObject)jsonDiff.get(\"destination\");\r\n\r\n      if (destinationPath == null) {\r\n        continue;  // Let's process the next item in \"objdiff_loop\"\r\n      }\r\n\r\n      String path = (String)destinationPath.get(\"toString\");\r\n      JsonArray jsonHunks = (JsonArray)jsonDiff.get(\"hunks\");\r\n\r\n      if (jsonHunks == null) {\r\n        continue;  // Let's process the next item in \"objdiff_loop\"\r\n      }\r\n\r\n      // calling the extracted section to scan the jsonHunks & jsonDiff into usable diffs\r\n      result.add(parseHunksIntoDiffs(path, jsonHunks, jsonDiff));\r\n\r\n      // Extract File Comments: this kind of comment will be attached to line 0\r\n      JsonArray jsonLineComments = (JsonArray)jsonDiff.get(\"fileComments\");\r\n\r\n      if (jsonLineComments == null) {\r\n        continue;  // Let's process the next item in \"objdiff_loop\"\r\n      }\r\n\r\n      StashDiff initialDiff = new StashDiff(IssueType.CONTEXT, path, 0, 0);\r\n\r\n      // Let's call this for loop \"objlinc_loop\"\r\n      for (Object objLineComment : jsonLineComments.toArray()) {\r\n\r\n        JsonObject jsonLineComment = (JsonObject)objLineComment;\r\n\r\n        long lineCommentId = getLong(jsonLineComment, \"id\");\r\n        String lineCommentMessage = (String)jsonLineComment.get(\"text\");\r\n        long lineCommentVersion = getLong(jsonLineComment, VERSION);\r\n\r\n        JsonObject objAuthor = (JsonObject)jsonLineComment.get(AUTHOR);\r\n\r\n        if (objAuthor == null) {\r\n          continue;  // Let's process the next item in \"objlinc_loop\"\r\n        }\r\n\r\n        StashUser author = extractUser(objAuthor);\r\n\r\n        StashComment comment = new StashComment(lineCommentId, lineCommentMessage, path,\r\n                                                (long)0, author, lineCommentVersion);\r\n        initialDiff.addComment(comment);\r\n      }\r\n\r\n      result.add(initialDiff);\r\n    }\r\n    return result;\r\n  }\r\n\r\n  private static StashDiffReport parseHunksIntoDiffs(String path, JsonArray jsonHunks, JsonObject jsonDiff) {\r\n\r\n    StashDiffReport result = new StashDiffReport();\r\n\r\n    // Let's call this for loop \"objhunk_loop\"\r\n    for (Object objHunk : jsonHunks.toArray()) {\r\n\r\n      JsonObject jsonHunk = (JsonObject)objHunk;\r\n      JsonArray jsonSegments = (JsonArray)jsonHunk.get(\"segments\");\r\n\r\n      if (jsonSegments == null) {\r\n        continue;  // Let's process the next item in \"objhunk_loop\"\r\n      }\r\n\r\n      // Let's call this for loop \"objsegm_loop\"\r\n      for (Object objSegment : jsonSegments.toArray()) {\r\n\r\n        JsonObject jsonSegment = (JsonObject)objSegment;\r\n        // type of the diff in diff view\r\n        // We filter REMOVED type, like useless for SQ analysis\r\n        IssueType type = IssueType.valueOf((String)jsonSegment.get(\"type\"));\r\n        //\r\n        JsonArray jsonLines = (JsonArray)jsonSegment.get(\"lines\");\r\n\r\n        if (type == IssueType.REMOVED || jsonLines == null) {\r\n\r\n          continue;  // Let's process the next item in \"objsegm_loop\"\r\n        }\r\n\r\n        // Let's call this for loop \"objline_loop\"\r\n        for (Object objLine : jsonLines.toArray()) {\r\n\r\n          JsonObject jsonLine = (JsonObject)objLine;\r\n          // destination line in diff view\r\n          long source = getLong(jsonLine, \"source\");\r\n          long destination = getLong(jsonLine,\"destination\");\r\n\r\n          StashDiff diff = new StashDiff(type, path, source, destination);\r\n          // Add comment attached to the current line\r\n          JsonArray jsonCommentIds = (JsonArray)jsonLine.get(\"commentIds\");\r\n\r\n          // To keep this method depth under control (squid:S134), we outsourced the comments extraction\r\n          result.add(extractCommentsForDiff(diff, jsonDiff, jsonCommentIds));\r\n        }\r\n      }\r\n    }\r\n    return result;\r\n  }\r\n\r\n  private static StashDiff extractCommentsForDiff(StashDiff diff, JsonObject jsonDiff, JsonArray jsonCommentIds) {\r\n\r\n    // If there is no comments, we just return the diff as-is\r\n    if (jsonCommentIds == null) {\r\n      return diff;\r\n    }\r\n\r\n    // Let's call this for loop \"objcomm_loop\"\r\n    for (Object objCommentId : jsonCommentIds.toArray()) {\r\n\r\n      long commentId = getLong(objCommentId);\r\n      JsonArray jsonLineComments = (JsonArray)jsonDiff.get(\"lineComments\");\r\n\r\n      if (jsonLineComments == null) {\r\n        continue;  // Let's process the next item in \"objcomm_loop\"\r\n      }\r\n\r\n      // Let's call this for loop \"objlico_loop\"\r\n      for (Object objLineComment : jsonLineComments.toArray()) {\r\n\r\n        JsonObject jsonLineComment = (JsonObject)objLineComment;\r\n\r\n        long lineCommentId = getLong(jsonLineComment, \"id\");\r\n\r\n        if (lineCommentId != commentId) {\r\n          continue;  // Let's process the next item in \"objcomm_loop\"\r\n        }\r\n\r\n        // Sending the JSON for processing into a nice comment\r\n        StashComment comment = buildCommentFromJSON(jsonLineComment, diff);\r\n\r\n        // If there is no valid comment in the JSON, we just consider the next element in \"objlico_loop\"\r\n        if (comment == null) {\r\n          continue;\r\n        }\r\n\r\n        // At this point, we can save the comment and add any relevant task to it\r\n        diff.addComment(comment);\r\n\r\n        // get the tasks linked to the current comment\r\n        updateCommentTasks(comment, (JsonArray)jsonLineComment.get(\"tasks\"));\r\n      }\r\n    }\r\n    return diff;\r\n  }\r\n\r\n  private static StashComment buildCommentFromJSON(JsonObject jsonLineComment, StashDiff diff) {\r\n\r\n    long lineCommentId = getLong(jsonLineComment, \"id\");\r\n\r\n    String lineCommentMessage = (String)jsonLineComment.get(\"text\");\r\n    long lineCommentVersion = getLong(jsonLineComment, VERSION);\r\n\r\n    JsonObject objAuthor = (JsonObject)jsonLineComment.get(AUTHOR);\r\n\r\n    if (objAuthor == null) {\r\n      return null;\r\n    }\r\n\r\n    StashUser author = extractUser(objAuthor);\r\n\r\n    return new StashComment(lineCommentId, lineCommentMessage, diff.getPath(),\r\n                            diff.getDestination(), author, lineCommentVersion);\r\n  }\r\n\r\n  private static void updateCommentTasks(StashComment comment, JsonArray jsonTasks) {\r\n\r\n    // No need to fail on NullPointerException but we want to keep caller's complexity down\r\n    if (jsonTasks == null) {\r\n      return;\r\n    }\r\n\r\n    for (Object objTask : jsonTasks.toArray()) {\r\n      JsonObject jsonTask = (JsonObject)objTask;\r\n\r\n      comment.addTask(extractTask(jsonTask));\r\n    }\r\n  }\r\n\r\n  public static StashTask extractTask(JsonObject jsonTask) {\r\n    long taskId = getLong(jsonTask, \"id\");\r\n    String taskText = (String)jsonTask.get(\"text\");\r\n    String taskState = (String)jsonTask.get(\"state\");\r\n\r\n    boolean deletable = true;\r\n\r\n    JsonObject objPermission = (JsonObject)jsonTask.get(\"permittedOperations\");\r\n    if (objPermission != null) {\r\n      deletable = (boolean)objPermission.get(\"deletable\");\r\n    }\r\n\r\n    return new StashTask(taskId, taskText, taskState, deletable);\r\n  }\r\n\r\n  public static boolean isLastPage(JsonObject jsonObject) {\r\n    if (jsonObject.get(\"isLastPage\") != null) {\r\n      return (Boolean)jsonObject.get(\"isLastPage\");\r\n    }\r\n    return true;\r\n  }\r\n\r\n  public static long getNextPageStart(JsonObject jsonObject) {\r\n\r\n    if (jsonObject.get(\"nextPageStart\") != null) {\r\n      return getLong(jsonObject,\"nextPageStart\");\r\n    }\r\n\r\n    return 0;\r\n  }\r\n\r\n  private static final Long getLong(JsonObject o, String name) {\r\n    return getLong(o.get(name));\r\n  }\r\n\r\n  private static final Long getLong(Object o) {\r\n    BigDecimal bd = (BigDecimal) o;\r\n    if (bd == null) {\r\n      return null;\r\n    }\r\n\r\n    return bd.longValue();\r\n  }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/resources/org/sonar/plugins/stash/sonar-stash.properties",
    "content": "project.version=${project.version}\nproject.name=${project.name}\n"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/CompleteITCase.java",
    "content": "package org.sonar.plugins.stash;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.sonar.plugins.stash.TestUtils.primeWireMock;\n\nimport com.github.tomakehurst.wiremock.client.WireMock;\nimport com.github.tomakehurst.wiremock.core.WireMockConfiguration;\nimport com.google.gson.JsonObject;\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Properties;\nimport java.util.stream.Collectors;\nimport org.apache.commons.lang3.StringUtils;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.TestInfo;\nimport org.junit.jupiter.api.extension.RegisterExtension;\nimport org.sonar.plugins.stash.fixtures.DummyStashServer;\nimport org.sonar.plugins.stash.fixtures.MavenSonarFixtures;\nimport org.sonar.plugins.stash.fixtures.SonarQubeRule;\nimport org.sonar.plugins.stash.fixtures.SonarScanner;\nimport org.sonar.plugins.stash.fixtures.WireMockExtension;\nimport org.sonar.plugins.stash.issue.StashUser;\nimport org.sonar.plugins.stash.issue.collector.DiffReportSample;\n\npublic class CompleteITCase {\n  protected static SonarScanner sonarScanner;\n  protected File sourcesDir;\n\n  protected static final StashUser user = new StashUser(\n      // has to match data in fixture\n      1,\"sonarqube\", \"sonarqube\", \"sq@example.com\"\n  );\n  protected static final String stashPassword = \"myPassword\";\n  protected static final String stashProject = \"PROJ\";\n  protected static final String stashRepo = \"REPO\";\n  protected String projectKey;\n  protected String projectName;\n  protected static final int stashPullRequest = 42;\n  protected DummyStashServer stash;\n  protected static final PullRequestRef pr = new PullRequestRef.Builder()\n      .setProject(stashProject)\n      .setRepository(stashRepo)\n      .setPullRequestId(stashPullRequest)\n      .build();\n\n  @RegisterExtension\n  public WireMockExtension wireMock = new WireMockExtension(\n      DummyStashServer.extend(WireMockConfiguration.options().dynamicPort()), true);\n\n  @RegisterExtension\n  public static SonarQubeRule sonarqube = new SonarQubeRule(MavenSonarFixtures.getSonarqube(9000));\n\n  @BeforeAll\n  public static void setUpClass() throws Exception {\n    sonarqube.get().installPlugin(new File(System.getProperty(\"test.plugin.archive\")));\n    sonarqube.start();\n\n    sonarScanner = MavenSonarFixtures.getSonarScanner();\n\n  }\n\n  @BeforeEach\n  public void setUp(TestInfo testInfo) throws Exception {\n    sourcesDir = Paths.get(\n        System.getProperty(\"test.sources.dir\"),\n        testInfo.getTestMethod().get().getName()\n    ).toFile();\n    projectKey = testInfo.getTestMethod().get().getName();\n    projectName = testInfo.getDisplayName();\n\n    sourcesDir.mkdirs();\n    sonarqube.get().createProject(projectKey, projectName);\n\n    primeWireMock(wireMock);\n    stash = new DummyStashServer(wireMock);\n    stash.mockUser(user);\n  }\n\n  @Test\n  public void testBasic() throws Exception {\n    stash.mockPrDiff(pr, DiffReportSample.baseReport);\n    stash.noCommentsFor(pr);\n    stash.expectCommentsUpdateFor(pr);\n\n    Properties props = new Properties();\n    props.put(\"sonar.sources\", \".\");\n    scan(true, true, props);\n    wireMock.verify(WireMock.getRequestedFor(WireMock.urlPathMatching(\".*\" + user.getSlug() + \"$\")));\n    wireMock.verify(WireMock.getRequestedFor(WireMock.urlPathMatching(\".*diff$\")));\n    wireMock.verify(WireMock.postRequestedFor(WireMock.urlPathMatching(\".*comments$\")));\n\n    // Making sure we find the proper agent info in a string like: User-Agent: SonarQube/4.5.7 Stash/1.2.0 AHC/1.0\n    wireMock.verify(WireMock.getRequestedFor(WireMock.anyUrl())\n                            .withHeader(\"User-Agent\", WireMock.matching(\"^(.*)Stash/[0-9.]+(.*)$\")));\n    wireMock.verify(WireMock.getRequestedFor(WireMock.anyUrl())\n                            .withHeader(\"User-Agent\", WireMock.matching(\"^(.*)SonarQube/[0-9.]+(.*)$\")));\n  }\n\n  @Test\n  public void testMultiModule() throws Exception {\n    installFile(\"sonar-project.properties\");\n    targetLocation(\"module1/src/main/java\").toFile().mkdirs();\n    targetLocation(\"module2/src/main/java\").toFile().mkdirs();\n\n    scan(false, false, null);\n\n    installFile(\"module1/src/main/java/Foo.java\");\n    installFile(\"module2/src/main/java/Bar.java\");\n\n\n    stash.mockPrDiff(\n        pr,\n        \"{\\\"fromHash\\\":\\\"bf19fb766666d80486aa81bc728a4e394ffa7ea8\\\",\\\"toHash\\\":\\\"79748088d6810b6e29eaa0319228fb8fecce14bb\\\",\\\"contextLines\\\":10,\\\"whitespace\\\":\\\"SHOW\\\",\\\"diffs\\\":[{\\\"source\\\":null,\\\"destination\\\":{\\\"components\\\":[\\\"module1\\\",\\\"src\\\",\\\"main\\\",\\\"java\\\",\\\"Foo.java\\\"],\\\"parent\\\":\\\"module1/src/main/java\\\",\\\"name\\\":\\\"Foo.java\\\",\\\"extension\\\":\\\"java\\\",\\\"toString\\\":\\\"module1/src/main/java/Foo.java\\\"},\\\"hunks\\\":[{\\\"sourceLine\\\":0,\\\"sourceSpan\\\":0,\\\"destinationLine\\\":1,\\\"destinationSpan\\\":5,\\\"segments\\\":[{\\\"type\\\":\\\"ADDED\\\",\\\"lines\\\":[{\\\"source\\\":0,\\\"destination\\\":1,\\\"line\\\":\\\"public class Foo {\\\",\\\"truncated\\\":false},{\\\"source\\\":0,\\\"destination\\\":2,\\\"line\\\":\\\"    public static void main(String[] args) {\\\",\\\"truncated\\\":false},{\\\"source\\\":0,\\\"destination\\\":3,\\\"line\\\":\\\"        System.out.println(\\\\\\\"Foo\\\\\\\");\\\",\\\"truncated\\\":false},{\\\"source\\\":0,\\\"destination\\\":4,\\\"line\\\":\\\"    }\\\",\\\"truncated\\\":false},{\\\"source\\\":0,\\\"destination\\\":5,\\\"line\\\":\\\"}\\\",\\\"truncated\\\":false}],\\\"truncated\\\":false}],\\\"truncated\\\":false}],\\\"truncated\\\":false},{\\\"source\\\":null,\\\"destination\\\":{\\\"components\\\":[\\\"module2\\\",\\\"src\\\",\\\"main\\\",\\\"java\\\",\\\"Bar.java\\\"],\\\"parent\\\":\\\"module2/src/main/java\\\",\\\"name\\\":\\\"Bar.java\\\",\\\"extension\\\":\\\"java\\\",\\\"toString\\\":\\\"module2/src/main/java/Bar.java\\\"},\\\"hunks\\\":[{\\\"sourceLine\\\":0,\\\"sourceSpan\\\":0,\\\"destinationLine\\\":1,\\\"destinationSpan\\\":5,\\\"segments\\\":[{\\\"type\\\":\\\"ADDED\\\",\\\"lines\\\":[{\\\"source\\\":0,\\\"destination\\\":1,\\\"line\\\":\\\"public class Bar {\\\",\\\"truncated\\\":false},{\\\"source\\\":0,\\\"destination\\\":2,\\\"line\\\":\\\"    public static void main(String[] args) {\\\",\\\"truncated\\\":false},{\\\"source\\\":0,\\\"destination\\\":3,\\\"line\\\":\\\"        System.out.println(\\\\\\\"Bar\\\\\\\");\\\",\\\"truncated\\\":false},{\\\"source\\\":0,\\\"destination\\\":4,\\\"line\\\":\\\"    }\\\",\\\"truncated\\\":false},{\\\"source\\\":0,\\\"destination\\\":5,\\\"line\\\":\\\"}\\\",\\\"truncated\\\":false}],\\\"truncated\\\":false}],\\\"truncated\\\":false}],\\\"truncated\\\":false}],\\\"truncated\\\":false}\"\n    );\n    stash.noCommentsFor(pr);\n    stash.expectCommentsUpdateFor(pr);\n\n    scan(true, true, null);\n\n    List<JsonObject> comments = stash.getCreatedComments();\n    assertThat(comments).hasSize(5);\n\n    List<JsonObject> overviewComment = comments.stream().filter(c -> !c.has(\"anchor\")).collect(Collectors.toList());\n    assertThat(overviewComment).hasSize(1);\n    assertThat(overviewComment.get(0).get(\"text\").getAsString()).contains(\"SonarQube analysis Overview\");\n\n    List<JsonObject> fileComments = comments.stream().filter(c -> c.has(\"anchor\")).collect(Collectors.toList());\n    assertThat(fileComments).hasSize(4);\n    assertThat(fileComments).extracting(o -> o.get(\"anchor\").getAsJsonObject().get(\"path\").getAsString()).containsOnly(\n        \"module1/src/main/java/Foo.java\", \"module2/src/main/java/Bar.java\"\n    );\n  }\n\n  private Path targetLocation(String name) {\n    return sourcesDir.toPath().resolve(name);\n  }\n\n  private void installFile(String name) throws IOException {\n    Path target = targetLocation(name);\n    target.getParent().toFile().mkdirs();\n    Files.copy(\n        getClass().getClassLoader().getResourceAsStream(\"foo/\" + name),\n        target\n    );\n  }\n\n  private String repoPath(String project, String repo, String... parts) {\n    return urlPath(\"rest\", \"api\", \"1.0\", \"projects\", project, \"repos\", repo, urlPath(false, parts));\n  }\n\n  private String urlPath(String... parts) {\n    return urlPath(true, parts);\n  }\n\n  private String urlPath(boolean leading, String... parts) {\n    String prefix = \"\";\n    if (leading) {\n      prefix = \"/\";\n    }\n    return prefix + StringUtils.join(parts, '/');\n  }\n\n  protected void scan(boolean activateSonarStash, boolean issuesMode, Properties properties) throws Exception {\n    List<File> sources = new ArrayList<>();\n    sources.add(sourcesDir);\n    Properties extraProps = new Properties();\n    //extraProps.setProperty(\"sonar.analysis.mode\", \"incremental\");\n    if (activateSonarStash) {\n      extraProps.setProperty(\"sonar.stash.url\", \"http://127.0.0.1:\" + wireMock.port());\n      extraProps.setProperty(\"sonar.stash.login\", user.getSlug());\n      extraProps.setProperty(\"sonar.stash.password\", stashPassword);\n      extraProps.setProperty(\"sonar.stash.notification\", \"true\");\n      extraProps.setProperty(\"sonar.stash.project\", stashProject);\n      extraProps.setProperty(\"sonar.stash.repository\", stashRepo);\n      extraProps.setProperty(\"sonar.stash.pullrequest.id\", String.valueOf(stashPullRequest));\n    }\n    if (issuesMode) {\n      extraProps.put(\"sonar.analysis.mode\", \"issues\");\n    }\n    extraProps.setProperty(\"sonar.log.level\", \"DEBUG\");\n\n    if (properties != null) {\n      extraProps.putAll(properties);\n    }\n    sonarScanner.scan(sonarqube.get(), sourcesDir, projectKey, projectName, \"0.0.0Final39\", extraProps);\n  }\n}\n"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/DefaultIssue.java",
    "content": "package org.sonar.plugins.stash;\n\nimport org.sonar.api.batch.fs.InputComponent;\nimport org.sonar.api.batch.postjob.issue.PostJobIssue;\nimport org.sonar.api.batch.rule.Severity;\nimport org.sonar.api.rule.RuleKey;\n\npublic class DefaultIssue implements PostJobIssue {\n  private String key, componentKey, message;\n  private InputComponent inputComponent;\n  private boolean isNew;\n  private Severity severity;\n  private Integer line;\n  private RuleKey ruleKey;\n\n  public String key() {\n    return key;\n  }\n\n  public DefaultIssue setKey(String key) {\n    this.key = key;\n    return this;\n  }\n\n  public String componentKey() {\n    return componentKey;\n  }\n\n  public DefaultIssue setComponentKey(String componentKey) {\n    this.componentKey = componentKey;\n    return this;\n  }\n\n  public String message() {\n    return message;\n  }\n\n  public DefaultIssue setMessage(String message) {\n    this.message = message;\n    return this;\n  }\n\n  public InputComponent inputComponent() {\n    return inputComponent;\n  }\n\n  public DefaultIssue setInputComponent(InputComponent inputComponent) {\n    this.inputComponent = inputComponent;\n    return this;\n  }\n\n  @Override\n  public boolean isNew() {\n    return isNew;\n  }\n\n  public DefaultIssue setNew(boolean aNew) {\n    isNew = aNew;\n    return this;\n  }\n\n  public Severity severity() {\n    return severity;\n  }\n\n  public DefaultIssue setSeverity(Severity severity) {\n    this.severity = severity;\n    return this;\n  }\n\n  public RuleKey ruleKey() {\n    return ruleKey;\n  }\n\n  public DefaultIssue setRuleKey(RuleKey ruleKey) {\n    this.ruleKey = ruleKey;\n    return this;\n  }\n\n  public DefaultIssue setLine(Integer line) {\n    this.line = line;\n    return this;\n  }\n\n  @Override\n  public Integer line() {\n    return line;\n  }\n}"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/DummyStashProjectBuilder.java",
    "content": "package org.sonar.plugins.stash;\n\nimport java.io.File;\n\npublic class DummyStashProjectBuilder extends StashProjectBuilder {\n  private File projectBaseDir;\n\n  public DummyStashProjectBuilder(File projectBaseDir) {\n    this.projectBaseDir = projectBaseDir;\n  }\n\n  @Override\n  public File getProjectBaseDir() {\n    return projectBaseDir;\n  }\n}\n"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/JavaUtilLoggingCapture.java",
    "content": "package org.sonar.plugins.stash;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.logging.ConsoleHandler;\nimport java.util.logging.Handler;\nimport java.util.logging.Level;\nimport java.util.logging.LogRecord;\nimport java.util.logging.Logger;\nimport java.util.logging.MemoryHandler;\n\npublic class JavaUtilLoggingCapture extends TestWatcherExtension {\n  private boolean gobbleOnSuccess;\n  private List<Handler> originalHandlers = new ArrayList<>();\n  private Level originalLevel;\n  private ConsoleHandler console = new ConsoleHandler();\n  private MemoryHandler spool = new MemoryHandler(console, 10000, Level.OFF);\n  private Logger logger;\n\n  public JavaUtilLoggingCapture(boolean gobbleOnSuccess) {\n    this.gobbleOnSuccess = gobbleOnSuccess;\n\n    logger = Logger.getGlobal();\n    Logger parent;\n    while ((parent = logger.getParent()) != null) {\n      logger = parent;\n    }\n  }\n\n  public JavaUtilLoggingCapture() {\n    this(true);\n  }\n\n  @Override\n  protected void succeeded() {\n    if (!gobbleOnSuccess) {\n      emit();\n    }\n  }\n\n  @Override\n  protected void failed() {\n    emit();\n  }\n\n  @Override\n  protected void finished() {\n    logger.removeHandler(spool);\n\n    for (Handler h : originalHandlers) {\n      logger.addHandler(h);\n    }\n    logger.setLevel(originalLevel);\n  }\n\n  @Override\n  protected void starting() {\n    for (Handler h : logger.getHandlers()) {\n      originalHandlers.add(h);\n      logger.removeHandler(h);\n    }\n    logger.addHandler(spool);\n\n    originalLevel = logger.getLevel();\n    logger.setLevel(Level.ALL);\n  }\n\n  private void emit() {\n    console.publish(new LogRecord(Level.SEVERE, \"Replaying captured log entries\"));\n    spool.push();\n    spool.flush();\n  }\n}\n"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/PeekableInputStreamTest.java",
    "content": "package org.sonar.plugins.stash;\n\nimport java.io.IOException;\nimport java.io.StringBufferInputStream;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\n\npublic class PeekableInputStreamTest {\n  @Test\n  public void testEmptyStream() throws IOException {\n    PeekableInputStream s = fromString(\"\");\n\n    assertFalse(s.peek().isPresent());\n    assertFalse(s.peek().isPresent());\n    assertFalse(s.peek().isPresent());\n  }\n\n  @Test\n  public void testStream() throws IOException {\n    PeekableInputStream s = fromString(\"abcde\");\n\n    assertEquals((Character)'a', s.peek().get());\n    assertEquals((Character)'a', s.peek().get());\n    assertEquals((Character)'a', s.peek().get());\n  }\n\n  private PeekableInputStream fromString(String s) {\n    return new PeekableInputStream(new StringBufferInputStream(s));\n  }\n}\n"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/PluginInfoTest.java",
    "content": "package org.sonar.plugins.stash;\r\n\r\nimport static org.junit.jupiter.api.Assertions.assertEquals;\r\n\r\nimport org.junit.jupiter.api.Test;\r\n\r\npublic class PluginInfoTest {\r\n\r\n  private static final String plugin_name = \"sonar-stash\";\r\n  private static final String plugin_vers = \"1337.0\";\r\n\r\n\r\n  @Test\r\n  public void testPluginInfoRef_ConstructorAndAccessors() {\r\n\r\n    PluginInfo PI = new PluginInfo(plugin_name, plugin_vers);\r\n\r\n    assertEquals(plugin_name, PI.getName());\r\n    assertEquals(plugin_vers, PI.getVersion());\r\n  }\r\n\r\n}"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/StashIssueReportingPostJobTest.java",
    "content": "package org.sonar.plugins.stash;\r\n\r\nimport static org.junit.jupiter.api.Assertions.assertFalse;\r\nimport static org.junit.jupiter.api.Assertions.assertTrue;\r\nimport static org.mockito.ArgumentMatchers.any;\r\nimport static org.mockito.ArgumentMatchers.anyString;\r\nimport static org.mockito.ArgumentMatchers.eq;\r\nimport static org.mockito.Mockito.mock;\r\nimport static org.mockito.Mockito.times;\r\nimport static org.mockito.Mockito.verify;\r\nimport static org.mockito.Mockito.when;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.Collection;\r\nimport java.util.List;\r\nimport java.util.Optional;\r\nimport org.junit.jupiter.api.BeforeEach;\r\nimport org.junit.jupiter.api.Test;\r\nimport org.junit.jupiter.api.extension.ExtendWith;\r\nimport org.mockito.Mock;\r\nimport org.mockito.junit.jupiter.MockitoExtension;\r\nimport org.mockito.junit.jupiter.MockitoSettings;\r\nimport org.mockito.quality.Strictness;\r\nimport org.sonar.api.batch.postjob.PostJobContext;\r\nimport org.sonar.api.batch.postjob.issue.PostJobIssue;\r\nimport org.sonar.api.batch.rule.Severity;\r\nimport org.sonar.api.platform.Server;\r\nimport org.sonar.plugins.stash.client.StashClient;\r\nimport org.sonar.plugins.stash.client.StashCredentials;\r\nimport org.sonar.plugins.stash.issue.StashDiffReport;\r\nimport org.sonar.plugins.stash.issue.StashUser;\r\n\r\n@ExtendWith(MockitoExtension.class)\r\n@MockitoSettings(strictness = Strictness.LENIENT)\r\npublic class StashIssueReportingPostJobTest extends StashTest {\r\n\r\n  private StashIssueReportingPostJob myJob;\r\n\r\n  @Mock\r\n  StashUser stashUser;\r\n\r\n  @Mock\r\n  StashRequestFacade stashRequestFacade;\r\n\r\n  @Mock\r\n  StashPluginConfiguration config;\r\n\r\n  @Mock\r\n  StashDiffReport diffReport;\r\n\r\n  @Mock\r\n  List<PostJobIssue> report;\r\n\r\n  @Mock\r\n  PostJobContext context;\r\n\r\n  @Mock\r\n  Server server;\r\n\r\n  private static final String STASH_PROJECT = \"Project\";\r\n  private static final String STASH_REPOSITORY = \"Repository\";\r\n  private static final int STASH_PULLREQUEST_ID = 1;\r\n  private static final String STASH_LOGIN = \"login@email.com\";\r\n  private static final String STASH_USER_SLUG = \"login\";\r\n  private static final String STASH_PASSWORD = \"password\";\r\n  private static final String STASH_URL = \"http://url/to/stash\";\r\n  private static final int STASH_TIMEOUT = 10000;\r\n  private static final int STASH_ISSUE_THRESHOLD = 100;\r\n  private static final PullRequestRef pr = PullRequestRef.builder()\r\n      .setProject(STASH_PROJECT)\r\n      .setRepository(STASH_REPOSITORY)\r\n      .setPullRequestId(STASH_PULLREQUEST_ID)\r\n      .build();\r\n\r\n\r\n  private static final String SONARQUBE_URL = \"http://url/to/sonarqube\";\r\n\r\n  @BeforeEach\r\n  public void setUp() throws Exception {\r\n    when(config.hasToNotifyStash()).thenReturn(true);\r\n    when(config.canApprovePullRequest()).thenReturn(false);\r\n    when(config.getStashURL()).thenReturn(STASH_URL);\r\n    when(config.getSonarQubeURL()).thenReturn(SONARQUBE_URL);\r\n    when(config.getStashTimeout()).thenReturn(STASH_TIMEOUT);\r\n    when(config.resetComments()).thenReturn(false);\r\n    when(config.hasToNotifyStash()).thenReturn(true);\r\n    when(config.includeAnalysisOverview()).thenReturn(Boolean.TRUE);\r\n\r\n    when(report.size()).thenReturn(10);\r\n    when(stashRequestFacade.extractIssueReport(eq(report)))\r\n        .thenReturn(report);\r\n    when(context.issues()).thenReturn(report);\r\n\r\n    when(stashRequestFacade.getIssueThreshold()).thenReturn(STASH_ISSUE_THRESHOLD);\r\n    when(stashRequestFacade.getStashProject()).thenReturn(STASH_PROJECT);\r\n    when(stashRequestFacade.getStashRepository()).thenReturn(STASH_REPOSITORY);\r\n    when(stashRequestFacade.getStashPullRequestId()).thenReturn(STASH_PULLREQUEST_ID);\r\n    when(stashRequestFacade.getCredentials()).thenReturn(new StashCredentials(STASH_LOGIN,\r\n        STASH_PASSWORD,\r\n        STASH_USER_SLUG));\r\n    when(stashRequestFacade\r\n        .getSonarQubeReviewer(anyString(), any(StashClient.class))).thenReturn(\r\n        stashUser);\r\n    when(stashRequestFacade.getPullRequestDiffReport(eq(pr), any()))\r\n        .thenReturn(diffReport);\r\n    when(stashRequestFacade.getIssueThreshold()).thenReturn(STASH_ISSUE_THRESHOLD);\r\n    when(stashRequestFacade.getStashURL()).thenReturn(STASH_URL);\r\n\r\n    when(stashRequestFacade.getPullRequest()).thenReturn(pr);\r\n  }\r\n\r\n  @Test\r\n  public void testExecuteOn() throws Exception {\r\n    myJob = new StashIssueReportingPostJob(config, stashRequestFacade, server);\r\n    myJob.execute(context);\r\n\r\n    verify(stashRequestFacade, times(0))\r\n        .resetComments(eq(pr), eq(diffReport), eq(stashUser), any());\r\n    verify(stashRequestFacade, times(1))\r\n        .postSonarQubeReport(eq(pr), eq(report), eq(diffReport), any());\r\n    verify(stashRequestFacade, times(1))\r\n        .postAnalysisOverview(eq(pr), eq(report),\r\n            any());\r\n    verify(stashRequestFacade, times(0))\r\n        .approvePullRequest(eq(pr), any());\r\n    verify(stashRequestFacade, times(0))\r\n        .resetPullRequestApproval(eq(pr), any());\r\n  }\r\n\r\n  @Test\r\n  public void testExecuteOnWithReachedThreshold() throws Exception {\r\n    when(stashRequestFacade.getIssueThreshold()).thenReturn(10);\r\n\r\n    List<PostJobIssue> report = mock(ArrayList.class);\r\n    when(report.size()).thenReturn(55);\r\n    when(stashRequestFacade.extractIssueReport(eq(report)))\r\n        .thenReturn(report);\r\n\r\n    myJob = new StashIssueReportingPostJob(config, stashRequestFacade, server);\r\n    myJob.execute(context);\r\n\r\n    verify(stashRequestFacade, times(0))\r\n        .resetComments(eq(pr), eq(diffReport), eq(stashUser), any());\r\n    verify(stashRequestFacade, times(0))\r\n        .postSonarQubeReport(eq(pr), eq(report), eq(diffReport), any());\r\n    verify(stashRequestFacade, times(1))\r\n        .postAnalysisOverview(eq(pr), any(Collection.class), any()\r\n        );\r\n  }\r\n\r\n  @Test\r\n  public void testExecuteOnWithNoPluginActivation() throws Exception {\r\n    when(config.hasToNotifyStash()).thenReturn(false);\r\n\r\n    myJob = new StashIssueReportingPostJob(config, stashRequestFacade, server);\r\n    myJob.execute(context);\r\n\r\n    verify(stashRequestFacade, times(0))\r\n        .resetComments(eq(pr), eq(diffReport), eq(stashUser), any());\r\n    verify(stashRequestFacade, times(0))\r\n        .postSonarQubeReport(eq(pr), eq(report), eq(diffReport), any());\r\n    verify(stashRequestFacade, times(0))\r\n        .postAnalysisOverview(eq(pr), eq(report), any());\r\n    verify(stashRequestFacade, times(0))\r\n        .approvePullRequest(eq(pr), any());\r\n    verify(stashRequestFacade, times(0))\r\n        .resetPullRequestApproval(eq(pr), any());\r\n  }\r\n\r\n  @Test\r\n  public void testExecuteOnWithNoStashUserDefined() throws Exception {\r\n    when(stashRequestFacade.getSonarQubeReviewer(anyString(), any())).thenReturn(null);\r\n\r\n    myJob = new StashIssueReportingPostJob(config, stashRequestFacade, server);\r\n    myJob.execute(context);\r\n\r\n    verify(stashRequestFacade, times(0))\r\n        .resetComments(eq(pr), eq(diffReport), eq(stashUser), any());\r\n    verify(stashRequestFacade, times(0))\r\n        .postSonarQubeReport(eq(pr), eq(report), eq(diffReport), any());\r\n    verify(stashRequestFacade, times(0))\r\n        .postAnalysisOverview(eq(pr), eq(report), any());\r\n    verify(stashRequestFacade, times(0))\r\n        .approvePullRequest(eq(pr), any());\r\n    verify(stashRequestFacade, times(0))\r\n        .resetPullRequestApproval(eq(pr), any());\r\n  }\r\n\r\n  @Test\r\n  public void testExecuteOnWithResetCommentActivated() throws Exception {\r\n    when(config.resetComments()).thenReturn(true);\r\n\r\n    myJob = new StashIssueReportingPostJob(config, stashRequestFacade, server);\r\n    myJob.execute(context);\r\n\r\n    verify(stashRequestFacade, times(1))\r\n        .resetComments(eq(pr), eq(diffReport), eq(stashUser), any());\r\n    verify(stashRequestFacade, times(1))\r\n        .postSonarQubeReport(eq(pr), eq(report), eq(diffReport), any());\r\n    verify(stashRequestFacade, times(1))\r\n        .postAnalysisOverview(eq(pr), eq(report), any());\r\n  }\r\n\r\n  @Test\r\n  public void testExecuteOnWithNoDiffReport() throws Exception {\r\n    diffReport = null;\r\n    when(stashRequestFacade.getPullRequestDiffReport(eq(pr), any()))\r\n        .thenReturn(diffReport);\r\n\r\n    myJob = new StashIssueReportingPostJob(config, stashRequestFacade, server);\r\n    myJob.execute(context);\r\n\r\n    verify(stashRequestFacade, times(0))\r\n        .resetComments(eq(pr), eq(diffReport), eq(stashUser), any());\r\n    verify(stashRequestFacade, times(0))\r\n        .postSonarQubeReport(eq(pr), eq(report), eq(diffReport), any());\r\n    verify(stashRequestFacade, times(0))\r\n        .postAnalysisOverview(eq(pr), eq(report), any());\r\n    verify(stashRequestFacade, times(0))\r\n        .approvePullRequest(eq(pr), any());\r\n    verify(stashRequestFacade, times(0))\r\n        .resetPullRequestApproval(eq(pr), any());\r\n  }\r\n\r\n  @Test\r\n  public void testShouldApprovePullRequest() {\r\n    PostJobIssue minorIssue = new DefaultIssue().setSeverity(Severity.MINOR);\r\n    PostJobIssue majorIssue = new DefaultIssue().setSeverity(Severity.MAJOR);\r\n\r\n    report = new ArrayList<>();\r\n\r\n    report.add(minorIssue);\r\n    report.add(majorIssue);\r\n\r\n    assertFalse(\r\n        StashIssueReportingPostJob.shouldApprovePullRequest(Optional.empty(), report)\r\n    );\r\n\r\n    report.clear();\r\n    assertTrue(\r\n        StashIssueReportingPostJob.shouldApprovePullRequest(Optional.empty(), report)\r\n    );\r\n\r\n    report.add(minorIssue);\r\n    assertTrue(\r\n        StashIssueReportingPostJob.shouldApprovePullRequest(Optional.of(Severity.MINOR), report)\r\n    );\r\n\r\n    report.add(majorIssue);\r\n    assertFalse(\r\n        StashIssueReportingPostJob.shouldApprovePullRequest(Optional.of(Severity.MINOR), report)\r\n    );\r\n  }\r\n}\r\n"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/StashPluginConfigurationTest.java",
    "content": "package org.sonar.plugins.stash;\r\n\r\nimport static org.junit.jupiter.api.Assertions.assertEquals;\r\nimport static org.junit.jupiter.api.Assertions.assertFalse;\r\nimport static org.junit.jupiter.api.Assertions.assertTrue;\r\n\r\nimport java.util.Optional;\r\nimport org.junit.jupiter.api.Test;\r\nimport org.sonar.api.CoreProperties;\r\nimport org.sonar.api.batch.rule.Severity;\r\nimport org.sonar.api.config.Settings;\r\nimport org.sonar.api.config.internal.MapSettings;\r\n\r\npublic class StashPluginConfigurationTest {\r\n\r\n\r\n  @Test\r\n  public void testStashPluginConfiguration_ConstructorAndAccessors() {\r\n\r\n    Integer SPRI = 1337;\r\n\r\n    Settings settings = new MapSettings();\r\n    settings.setProperty(StashPlugin.STASH_NOTIFICATION, true);\r\n    settings.setProperty(StashPlugin.STASH_PROJECT, \"take-over-the-world\");\r\n    settings.setProperty(StashPlugin.STASH_REPOSITORY, \"death-ray\");\r\n    settings.setProperty(StashPlugin.STASH_PULL_REQUEST_ID, SPRI);\r\n    settings.setProperty(StashPlugin.STASH_URL, \"https://stash\");\r\n    settings.setProperty(StashPlugin.STASH_LOGIN, \"me\");\r\n    settings.setProperty(StashPlugin.STASH_USER_SLUG, \"mini.me\");\r\n    settings.setProperty(StashPlugin.STASH_PASSWORD, \"unsecure\");\r\n    settings.setProperty(StashPlugin.STASH_PASSWORD_ENVIRONMENT_VARIABLE, \"you-should-not\");\r\n\r\n    settings.setProperty(CoreProperties.LOGIN, \"him\");\r\n    settings.setProperty(CoreProperties.PASSWORD, \"notsafe\");\r\n    settings.setProperty(StashPlugin.STASH_ISSUE_THRESHOLD, 42000);\r\n    settings.setProperty(StashPlugin.STASH_ISSUE_SEVERITY_THRESHOLD, \"MINOR\");\r\n    settings.setProperty(StashPlugin.STASH_TIMEOUT, 42);\r\n    settings.setProperty(StashPlugin.STASH_REVIEWER_APPROVAL, true);\r\n    settings.setProperty(StashPlugin.STASH_RESET_COMMENTS, false);\r\n    settings.setProperty(StashPlugin.STASH_TASK_SEVERITY_THRESHOLD, \"MINOR\");\r\n    settings.setProperty(StashPlugin.STASH_INCLUDE_ANALYSIS_OVERVIEW, true);\r\n    //Optional getRepositoryRoot() ???\r\n\r\n    StashPluginConfiguration SPC = new StashPluginConfiguration(settings, null);\r\n\r\n    assertTrue(SPC.hasToNotifyStash());\r\n    assertEquals(\"take-over-the-world\", SPC.getStashProject());\r\n    assertEquals(\"death-ray\", SPC.getStashRepository());\r\n    assertEquals(SPRI, SPC.getPullRequestId());\r\n    assertEquals(\"https://stash\", SPC.getStashURL());\r\n    assertEquals(\"me\", SPC.getStashLogin());\r\n    assertEquals(\"mini.me\", SPC.getStashUserSlug());\r\n    assertEquals(\"unsecure\", SPC.getStashPassword());\r\n    assertEquals(\"you-should-not\", SPC.getStashPasswordEnvironmentVariable());\r\n\r\n    assertEquals(\"him\", SPC.getSonarQubeLogin());\r\n    assertEquals(\"notsafe\", SPC.getSonarQubePassword());\r\n    assertEquals(42000, SPC.getIssueThreshold());\r\n    assertEquals(Severity.MINOR, SPC.getIssueSeverityThreshold());\r\n    assertEquals(42, SPC.getStashTimeout());\r\n    assertTrue(SPC.canApprovePullRequest());\r\n    assertFalse(SPC.resetComments());\r\n    assertEquals(Optional.of(Severity.MINOR), SPC.getTaskIssueSeverityThreshold());\r\n    assertTrue(SPC.includeAnalysisOverview());\r\n    //assertEquals(, SPC.getRepositoryRoot());\r\n\r\n    settings.setProperty(StashPlugin.STASH_TASK_SEVERITY_THRESHOLD, \"NONE\");\r\n    assertEquals(Optional.empty(), SPC.getTaskIssueSeverityThreshold());\r\n  }\r\n\r\n}"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/StashPluginUtilsTest.java",
    "content": "package org.sonar.plugins.stash;\r\n\r\nimport org.junit.jupiter.api.Test;\r\n\r\nimport static org.junit.jupiter.api.Assertions.assertEquals;\r\nimport static org.junit.jupiter.api.Assertions.assertFalse;\r\nimport static org.junit.jupiter.api.Assertions.assertTrue;\r\nimport static org.sonar.plugins.stash.StashPluginUtils.formatPercentage;\r\nimport static org.sonar.plugins.stash.StashPluginUtils.roundedPercentageGreaterThan;\r\n\r\n\r\npublic class StashPluginUtilsTest {\r\n\r\n  @Test\r\n  public void testFormatPercentage() {\r\n    assertEquals(\"10.9\", formatPercentage(10.90));\r\n    assertEquals(\"10.9\", formatPercentage(10.94));\r\n    assertEquals(\"11.0\", formatPercentage(10.96));\r\n    assertEquals(\"11.0\", formatPercentage(11.0));\r\n    assertEquals(\"31.3\", formatPercentage(31.25));\r\n    assertEquals(\"50.3\", formatPercentage(50.29));\r\n    // This test can fail with 50.2 instead of 50.3 if run with an older version of the JDK 8\r\n    //    (failed with v25 & worked with v131)\r\n  }\r\n\r\n  @Test\r\n  public void testRoundedPercentageGreaterThan() {\r\n    assertTrue(roundedPercentageGreaterThan(0.1, 0.0));\r\n    assertTrue(roundedPercentageGreaterThan(0.2, 0.1));\r\n    assertTrue(roundedPercentageGreaterThan(1, 0.1));\r\n    assertTrue(roundedPercentageGreaterThan(1.1, 0.1));\r\n\r\n    assertFalse(roundedPercentageGreaterThan(0.0, 0.1));\r\n    assertFalse(roundedPercentageGreaterThan(0.1, 0.2));\r\n    assertFalse(roundedPercentageGreaterThan(1.1, 1.2));\r\n\r\n    assertFalse(roundedPercentageGreaterThan(1.01, 1.00));\r\n    assertFalse(roundedPercentageGreaterThan(1.04, 1.00));\r\n\r\n    assertTrue(roundedPercentageGreaterThan(1.05, 1.00));\r\n  }\r\n}\r\n"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/StashRequestFacadeTest.java",
    "content": "package org.sonar.plugins.stash;\n\nimport java.nio.file.FileSystems;\nimport java.nio.file.Path;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.junit.jupiter.api.extension.RegisterExtension;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\nimport org.mockito.junit.jupiter.MockitoSettings;\nimport org.mockito.quality.Strictness;\nimport org.sonar.api.batch.fs.internal.DefaultInputFile;\nimport org.sonar.api.batch.postjob.issue.PostJobIssue;\nimport org.sonar.api.batch.rule.Severity;\nimport org.sonar.api.rule.RuleKey;\nimport org.sonar.api.utils.System2;\nimport org.sonar.plugins.stash.StashPlugin.IssueType;\nimport org.sonar.plugins.stash.client.StashClient;\nimport org.sonar.plugins.stash.client.StashCredentials;\nimport org.sonar.plugins.stash.exceptions.StashClientException;\nimport org.sonar.plugins.stash.exceptions.StashConfigurationException;\nimport org.sonar.plugins.stash.fixtures.DummyIssuePathResolver;\nimport org.sonar.plugins.stash.issue.MarkdownPrinter;\nimport org.sonar.plugins.stash.issue.StashComment;\nimport org.sonar.plugins.stash.issue.StashCommentReport;\nimport org.sonar.plugins.stash.issue.StashDiffReport;\nimport org.sonar.plugins.stash.issue.StashPullRequest;\nimport org.sonar.plugins.stash.issue.StashTask;\nimport org.sonar.plugins.stash.issue.StashUser;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Optional;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyCollection;\nimport static org.mockito.ArgumentMatchers.anyInt;\nimport static org.mockito.ArgumentMatchers.anyLong;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.Mockito.doNothing;\nimport static org.mockito.Mockito.doReturn;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.spy;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\nimport static org.sonar.plugins.stash.TestUtils.inputFile;\n\n\n@ExtendWith(MockitoExtension.class)\n@MockitoSettings(strictness = Strictness.LENIENT)\npublic class StashRequestFacadeTest extends StashTest {\n  StashRequestFacade myFacade;\n\n  @Mock\n  StashPluginConfiguration config;\n\n  @Mock\n  StashClient stashClient;\n\n  @Mock\n  StashDiffReport diffReport;\n\n  @Mock\n  StashCommentReport stashCommentsReport1;\n\n  @Mock\n  StashCommentReport stashCommentsReport2;\n\n  @Mock\n  StashComment comment1;\n\n  @Mock\n  StashComment comment2;\n\n  @Mock\n  StashComment comment3;\n\n  @Mock\n  StashUser stashUser;\n\n  @Mock\n  System2 system;\n\n  String stashCommentMessage1;\n  String stashCommentMessage2;\n  String stashCommentMessage3;\n\n  List<PostJobIssue> report;\n\n  StashProjectBuilder spr;\n\n  private static final String STASH_PROJECT = \"Project\";\n  private static final String STASH_REPOSITORY = \"Repository\";\n  private static final int STASH_PULLREQUEST_ID = 1;\n  private static final PullRequestRef pr = PullRequestRef.builder()\n                                                         .setProject(STASH_PROJECT)\n                                                         .setRepository(STASH_REPOSITORY)\n                                                         .setPullRequestId(STASH_PULLREQUEST_ID)\n                                                         .build();\n\n  private static final IssueType STASH_DIFF_TYPE = IssueType.CONTEXT;\n  private static final String STASH_USER = \"SonarQube\";\n  private static final String STASH_URL = \"http://stash/url\";\n\n  private static final String SONARQUBE_URL = \"http://sonar/url\";\n\n  private static final String FILE_PATH_1 = \"path/to/file1\";\n  private static final String FILE_PATH_2 = \"path/to/file2\";\n\n  @BeforeEach\n  public void setUp() throws Exception {\n\n    config = mock(StashPluginConfiguration.class);\n    when(config.getTaskIssueSeverityThreshold()).thenReturn(Optional.empty());\n    when(config.getIssueSeverityThreshold()).thenReturn(Severity.INFO);\n    when(config.getSonarQubeURL()).thenReturn(SONARQUBE_URL);\n    when(config.getStashURL()).thenReturn(STASH_URL);\n    when(config.getStashProject()).thenReturn(STASH_PROJECT);\n    when(config.getStashRepository()).thenReturn(STASH_REPOSITORY);\n    when(config.getRepositoryRoot()).thenReturn(Optional.empty());\n\n    when(system.envVariable(any())).thenReturn(null);\n\n    spr = new DummyStashProjectBuilder(new File(\"/basedir\"));\n\n    StashRequestFacade facade = new StashRequestFacade(config, spr, system);\n    myFacade = spy(facade);\n\n    stashClient = mock(StashClient.class);\n\n    diffReport = mock(StashDiffReport.class);\n\n    when(diffReport.getType(anyString(), anyLong(), anyInt())).thenReturn(STASH_DIFF_TYPE);\n    when(diffReport.getLine(FILE_PATH_1, 1)).thenReturn((long)1);\n    when(diffReport.getLine(FILE_PATH_1, 2)).thenReturn((long)2);\n    when(diffReport.getLine(FILE_PATH_2, 1)).thenReturn((long)1);\n\n    stashUser = mock(StashUser.class);\n    when(stashUser.getId()).thenReturn((long) 1234);\n\n    MarkdownPrinter printer = new MarkdownPrinter(100, SONARQUBE_URL, 0, new DummyIssuePathResolver());\n\n    report = new ArrayList<PostJobIssue>();\n\n    Path moduleBaseDir = FileSystems.getDefault().getPath(\"some\", \"dir\");\n\n    PostJobIssue issue1 = new DefaultIssue().setKey(\"key1\")\n                                     .setSeverity(Severity.CRITICAL)\n                                     .setMessage(\"message1\")\n                                     .setRuleKey(RuleKey.of(\"foo\", \"rule1\"))\n                                     .setInputComponent(inputFile(\"module1\", moduleBaseDir, \"/basedir/\" + FILE_PATH_1))\n                                     .setLine(1);\n    stashCommentMessage1 = printer.printIssueMarkdown(issue1);\n    report.add(issue1);\n\n    PostJobIssue issue2 = new DefaultIssue().setKey(\"key2\")\n                                     .setSeverity(Severity.MAJOR)\n                                     .setMessage(\"message2\")\n                                     .setRuleKey(RuleKey.of(\"foo\", \"rule2\"))\n                                     .setInputComponent(inputFile(\"module2\", moduleBaseDir, \"/basedir/\" + FILE_PATH_1))\n                                     .setLine(2);\n    stashCommentMessage2 = printer.printIssueMarkdown(issue2);\n    report.add(issue2);\n\n\n    PostJobIssue issue3 = new DefaultIssue().setKey(\"key3\")\n                                     .setSeverity(Severity.INFO)\n                                     .setMessage(\"message3\")\n                                     .setRuleKey(RuleKey.of(\"foo\", \"rule3\"))\n                                     .setInputComponent(inputFile(\"module3\", moduleBaseDir, \"/basedir/\" + FILE_PATH_2))\n                                     .setLine(1);\n    stashCommentMessage3 = printer.printIssueMarkdown(issue3);\n    report.add(issue3);\n\n    StashTask task1 = mock(StashTask.class);\n    when(task1.getId()).thenReturn((long)1111);\n\n    List<StashTask> taskList1 = new ArrayList<>();\n    taskList1.add(task1);\n\n    comment1 = mock(StashComment.class);\n    when(comment1.getId()).thenReturn((long)1111);\n    when(comment1.getAuthor()).thenReturn(stashUser);\n    when(stashClient.postCommentLineOnPullRequest(pr,\n                                                  stashCommentMessage1,\n                                                  FILE_PATH_1,\n                                                  1,\n                                                  STASH_DIFF_TYPE)).thenReturn(comment1);\n    when(comment1.getTasks()).thenReturn(taskList1);\n    when(comment1.containsPermanentTasks()).thenReturn(false);\n\n    StashTask task2 = mock(StashTask.class);\n    when(task1.getId()).thenReturn((long)2222);\n\n    List<StashTask> taskList2 = new ArrayList<>();\n    taskList2.add(task2);\n\n    comment2 = mock(StashComment.class);\n    when(comment2.getId()).thenReturn((long)2222);\n    when(comment2.getAuthor()).thenReturn(stashUser);\n    when(stashClient.postCommentLineOnPullRequest(pr,\n                                                  stashCommentMessage2,\n                                                  FILE_PATH_1,\n                                                  2,\n                                                  STASH_DIFF_TYPE)).thenReturn(comment2);\n    when(comment2.getTasks()).thenReturn(taskList2);\n    when(comment2.containsPermanentTasks()).thenReturn(false);\n\n    StashTask task3 = mock(StashTask.class);\n    when(task3.getId()).thenReturn((long)3333);\n\n    List<StashTask> taskList3 = new ArrayList<>();\n    taskList3.add(task3);\n\n    comment3 = mock(StashComment.class);\n    when(comment3.getId()).thenReturn((long)3333);\n    when(comment3.getAuthor()).thenReturn(stashUser);\n    when(stashClient.postCommentLineOnPullRequest(pr,\n                                                  stashCommentMessage3,\n                                                  FILE_PATH_2,\n                                                  1,\n                                                  STASH_DIFF_TYPE)).thenReturn(comment3);\n    when(comment3.getTasks()).thenReturn(taskList3);\n    when(comment3.containsPermanentTasks()).thenReturn(false);\n\n    ArrayList<StashComment> comments = new ArrayList<>();\n    comments.add(comment1);\n    comments.add(comment2);\n    comments.add(comment3);\n\n    when(diffReport.getComments()).thenReturn(comments);\n\n    stashCommentsReport1 = mock(StashCommentReport.class);\n    when(stashCommentsReport1.getComments()).thenReturn(comments);\n    when(stashCommentsReport1.applyDiffReport(diffReport)).thenReturn(stashCommentsReport1);\n    when(stashClient.getPullRequestComments(pr, \"path/to/file1\")).thenReturn(stashCommentsReport1);\n\n    stashCommentsReport2 = mock(StashCommentReport.class);\n    when(stashCommentsReport1.getComments()).thenReturn(comments);\n    when(stashCommentsReport2.applyDiffReport(diffReport)).thenReturn(stashCommentsReport2);\n    when(stashClient.getPullRequestComments(pr, \"path/to/file2\")).thenReturn(stashCommentsReport2);\n\n    doNothing().when(stashClient).deletePullRequestComment(eq(pr), any(StashComment.class));\n    doNothing().when(stashClient).deleteTaskOnComment(any(StashTask.class));\n  }\n\n  @Test\n  public void testGetCredentials() throws StashConfigurationException {\n    when(config.getStashLogin()).thenReturn(\"login\");\n    when(config.getStashPassword()).thenReturn(\"password\");\n\n    StashCredentials credentials = myFacade.getCredentials();\n    assertEquals(\"login\", credentials.getLogin());\n    assertEquals(\"password\", credentials.getPassword());\n  }\n\n  @Test\n  public void testGetNoCredentials() throws StashConfigurationException {\n    when(config.getStashLogin()).thenReturn(null);\n    when(config.getStashPassword()).thenReturn(null);\n\n    StashCredentials credentials = myFacade.getCredentials();\n    assertNull(credentials.getLogin());\n    assertNull(credentials.getPassword());\n  }\n\n  @Test\n  public void testGetPasswordFromEnvironment() throws StashConfigurationException {\n    when(config.getStashLogin()).thenReturn(\"login\");\n    when(config.getStashPasswordEnvironmentVariable()).thenReturn(\"SONAR_STASH_PASSWORD\");\n    when(system.envVariable(\"SONAR_STASH_PASSWORD\")).thenReturn(\"envPassword\");\n\n    StashCredentials credentials = myFacade.getCredentials();\n    assertEquals(\"envPassword\", credentials.getPassword());\n\n    when(config.getStashPassword()).thenReturn(\"password\");\n    credentials = myFacade.getCredentials();\n    assertEquals(\"envPassword\", credentials.getPassword());\n  }\n\n  @Test\n  public void testGetPasswordFromUnconfiguredEnvironment() throws StashConfigurationException {\n    when(config.getStashLogin()).thenReturn(\"login\");\n    when(config.getStashPasswordEnvironmentVariable()).thenReturn(\"SONAR_STASH_PASSWORD\");\n\n    assertThrows(StashConfigurationException.class, () ->\n        myFacade.getCredentials()\n    );\n  }\n\n  @Test\n  public void testGetIssueThreshold() throws StashConfigurationException {\n    when(config.getIssueThreshold()).thenReturn(1);\n    assertEquals(1, myFacade.getIssueThreshold());\n  }\n\n  @Test\n  public void testGetIssueThresholdThrowsException() throws StashConfigurationException {\n    when(config.getIssueThreshold()).thenThrow(new NumberFormatException());\n\n    assertThrows(StashConfigurationException.class, () ->\n        myFacade.getIssueThreshold()\n    );\n  }\n\n  @Test\n  public void testGetStashURL() throws StashConfigurationException {\n    when(config.getStashURL()).thenReturn(\"http://url\");\n    assertEquals(\"http://url\", myFacade.getStashURL());\n\n    when(config.getStashURL()).thenReturn(\"http://url/\");\n    assertEquals(\"http://url\", myFacade.getStashURL());\n  }\n\n  @Test\n  public void testGetStashURLThrowsException() throws StashConfigurationException {\n    when(config.getStashURL()).thenReturn(null);\n\n    assertThrows(StashConfigurationException.class, () ->\n        myFacade.getStashURL()\n    );\n  }\n\n  @Test\n  public void testGetStashProject() throws StashConfigurationException {\n    when(config.getStashProject()).thenReturn(\"project\");\n    assertEquals(\"project\", myFacade.getStashProject());\n  }\n\n  @Test\n  public void testGetStashProjectThrowsException() throws StashConfigurationException {\n    when(config.getStashProject()).thenReturn(null);\n    assertThrows(StashConfigurationException.class, () ->\n        myFacade.getStashProject()\n    );\n  }\n\n  @Test\n  public void testGetStashRepository() throws StashConfigurationException {\n    when(config.getStashRepository()).thenReturn(\"repository\");\n    assertEquals(\"repository\", myFacade.getStashRepository());\n  }\n\n  @Test\n  public void testGetStashRepositoryThrowsException() throws StashConfigurationException {\n    when(config.getStashRepository()).thenReturn(null);\n    assertThrows(StashConfigurationException.class, () ->\n        myFacade.getStashRepository()\n    );\n  }\n\n  @Test\n  public void testGetStashPullRequestId() throws StashConfigurationException {\n    when(config.getPullRequestId()).thenReturn(12345);\n    assertEquals(12345, myFacade.getStashPullRequestId());\n  }\n\n  @Test\n  public void testGetStashPullRequestIdThrowsException() throws StashConfigurationException {\n    when(config.getPullRequestId()).thenReturn(null);\n    assertThrows(StashConfigurationException.class, () ->\n        myFacade.getStashPullRequestId()\n    );\n  }\n\n  @Test\n  public void testPostCommentPerIssue() throws Exception {\n    when(stashCommentsReport1.contains(stashCommentMessage1, FILE_PATH_1, 1)).thenReturn(true);\n    when(stashCommentsReport1.contains(stashCommentMessage2, FILE_PATH_1, 2)).thenReturn(false);\n    when(stashCommentsReport2.contains(stashCommentMessage3, FILE_PATH_2, 1)).thenReturn(false);\n\n    myFacade.postCommentPerIssue(pr, report, diffReport, stashClient);\n\n    verify(stashClient, times(0)).postCommentLineOnPullRequest(pr,\n                                                               stashCommentMessage1,\n                                                               FILE_PATH_1,\n                                                               1,\n                                                               STASH_DIFF_TYPE);\n    verify(stashClient, times(1)).postCommentLineOnPullRequest(pr,\n                                                               stashCommentMessage2,\n                                                               \"path/to/file1\",\n                                                               2,\n                                                               STASH_DIFF_TYPE);\n    verify(stashClient, times(1)).postCommentLineOnPullRequest(pr,\n                                                               stashCommentMessage3,\n                                                               \"path/to/file2\",\n                                                               1,\n                                                               STASH_DIFF_TYPE);\n  }\n\n  @Test\n  public void testPostCommentPerIssueWithNoStashCommentAlreadyPushed() throws Exception {\n    when(stashCommentsReport1.contains(stashCommentMessage1, FILE_PATH_1, 1)).thenReturn(true);\n    when(stashCommentsReport1.contains(stashCommentMessage2, FILE_PATH_1, 2)).thenReturn(true);\n    when(stashCommentsReport2.contains(stashCommentMessage3, FILE_PATH_2, 1)).thenReturn(true);\n\n    myFacade.postCommentPerIssue(pr, report, diffReport, stashClient);\n\n    verify(stashClient, times(0)).postCommentLineOnPullRequest(pr,\n                                                               stashCommentMessage1,\n                                                               FILE_PATH_1,\n                                                               1,\n                                                               STASH_DIFF_TYPE);\n    verify(stashClient, times(0)).postCommentLineOnPullRequest(pr,\n                                                               stashCommentMessage2,\n                                                               FILE_PATH_1,\n                                                               2,\n                                                               STASH_DIFF_TYPE);\n    verify(stashClient, times(0)).postCommentLineOnPullRequest(pr,\n                                                               stashCommentMessage3,\n                                                               FILE_PATH_2,\n                                                               1,\n                                                               STASH_DIFF_TYPE);\n  }\n\n  @Test\n  public void testPostCommentPerIssueIgnoresLowerSeverityIssues() throws Exception {\n    when(config.getIssueSeverityThreshold()).thenReturn(Severity.MAJOR);\n    when(stashCommentsReport1.contains(stashCommentMessage1, FILE_PATH_1, 1)).thenReturn(true);\n    when(stashCommentsReport1.contains(stashCommentMessage2, FILE_PATH_1, 2)).thenReturn(false);\n    when(stashCommentsReport2.contains(stashCommentMessage3, FILE_PATH_2, 1)).thenReturn(false);\n\n    myFacade.postCommentPerIssue(pr, report, diffReport, stashClient);\n\n    verify(stashClient, times(0)).postCommentLineOnPullRequest(pr,\n                                                               stashCommentMessage1,\n                                                               FILE_PATH_1,\n                                                               1,\n                                                               STASH_DIFF_TYPE);\n    verify(stashClient, times(1)).postCommentLineOnPullRequest(pr,\n                                                               stashCommentMessage2,\n                                                               \"path/to/file1\",\n                                                               2,\n                                                               STASH_DIFF_TYPE);\n    verify(stashClient, times(0)).postCommentLineOnPullRequest(pr,\n                                                               stashCommentMessage3,\n                                                               \"path/to/file2\",\n                                                               1,\n                                                               STASH_DIFF_TYPE);\n  }\n\n  @Test\n  public void testPostSonarQubeReport() throws StashClientException, StashConfigurationException {\n    myFacade.postSonarQubeReport(pr, report, diffReport, stashClient);\n    verify(myFacade, times(1)).postCommentPerIssue(eq(pr),\n                                                   anyCollection(),\n                                                   eq(diffReport),\n                                                   eq(stashClient));\n  }\n\n  @Test\n  public void testPostTaskOnComment() throws Exception {\n    when(config.getTaskIssueSeverityThreshold()).thenReturn(Optional.of(Severity.INFO));\n\n    myFacade.postSonarQubeReport(pr, report, diffReport, stashClient);\n\n    verify(stashClient, times(1)).postCommentLineOnPullRequest(pr,\n                                                               stashCommentMessage1,\n                                                               FILE_PATH_1,\n                                                               1,\n                                                               STASH_DIFF_TYPE);\n    verify(stashClient, times(1)).postCommentLineOnPullRequest(pr,\n                                                               stashCommentMessage2,\n                                                               FILE_PATH_1,\n                                                               2,\n                                                               STASH_DIFF_TYPE);\n    verify(stashClient, times(1)).postCommentLineOnPullRequest(pr,\n                                                               stashCommentMessage3,\n                                                               FILE_PATH_2,\n                                                               1,\n                                                               STASH_DIFF_TYPE);\n\n    verify(stashClient, times(1)).postTaskOnComment(\"message3\", (long)3333);\n    verify(stashClient, times(1)).postTaskOnComment(\"message2\", (long)2222);\n    verify(stashClient, times(1)).postTaskOnComment(\"message1\", (long)1111);\n  }\n\n  @Test\n  public void testPostTaskOnCommentWithRestrictedLevel() throws Exception {\n    when(config.getTaskIssueSeverityThreshold()).thenReturn(Optional.of(Severity.MAJOR));\n\n    myFacade.postSonarQubeReport(pr, report, diffReport, stashClient);\n\n    verify(stashClient, times(1)).postCommentLineOnPullRequest(pr,\n                                                               stashCommentMessage1,\n                                                               FILE_PATH_1,\n                                                               1,\n                                                               STASH_DIFF_TYPE);\n    verify(stashClient, times(1)).postCommentLineOnPullRequest(pr,\n                                                               stashCommentMessage2,\n                                                               FILE_PATH_1,\n                                                               2,\n                                                               STASH_DIFF_TYPE);\n    verify(stashClient, times(1)).postCommentLineOnPullRequest(pr,\n                                                               stashCommentMessage3,\n                                                               FILE_PATH_2,\n                                                               1,\n                                                               STASH_DIFF_TYPE);\n\n    verify(stashClient, times(0)).postTaskOnComment(\"message3\", (long)3333);\n    verify(stashClient, times(1)).postTaskOnComment(\"message2\", (long)2222);\n    verify(stashClient, times(1)).postTaskOnComment(\"message1\", (long)1111);\n  }\n\n  @Test\n  public void testPostTaskOnCommentWithNotPresentLevel() throws Exception {\n    when(config.getTaskIssueSeverityThreshold()).thenReturn(Optional.of(Severity.BLOCKER));\n\n    myFacade.postSonarQubeReport(pr, report, diffReport, stashClient);\n\n    verify(stashClient, times(1)).postCommentLineOnPullRequest(pr,\n                                                               stashCommentMessage1,\n                                                               FILE_PATH_1,\n                                                               1,\n                                                               STASH_DIFF_TYPE);\n    verify(stashClient, times(1)).postCommentLineOnPullRequest(pr,\n                                                               stashCommentMessage2,\n                                                               FILE_PATH_1,\n                                                               2,\n                                                               STASH_DIFF_TYPE);\n    verify(stashClient, times(1)).postCommentLineOnPullRequest(pr,\n                                                               stashCommentMessage3,\n                                                               FILE_PATH_2,\n                                                               1,\n                                                               STASH_DIFF_TYPE);\n\n    verify(stashClient, times(0)).postTaskOnComment(\"message3\", (long)3333);\n    verify(stashClient, times(0)).postTaskOnComment(\"message2\", (long)2222);\n    verify(stashClient, times(0)).postTaskOnComment(\"message1\", (long)1111);\n  }\n\n  @Test\n  public void testPostTaskOnCommentWithSeverityNone() throws Exception {\n    when(config.getTaskIssueSeverityThreshold()).thenReturn(Optional.empty());\n\n    myFacade.postSonarQubeReport(pr, report, diffReport, stashClient);\n\n    verify(stashClient, times(1)).postCommentLineOnPullRequest(pr,\n                                                               stashCommentMessage1,\n                                                               FILE_PATH_1,\n                                                               1,\n                                                               STASH_DIFF_TYPE);\n    verify(stashClient, times(1)).postCommentLineOnPullRequest(pr,\n                                                               stashCommentMessage2,\n                                                               FILE_PATH_1,\n                                                               2,\n                                                               STASH_DIFF_TYPE);\n    verify(stashClient, times(1)).postCommentLineOnPullRequest(pr,\n                                                               stashCommentMessage3,\n                                                               FILE_PATH_2,\n                                                               1,\n                                                               STASH_DIFF_TYPE);\n\n    verify(stashClient, times(0)).postTaskOnComment(\"message3\", (long)3333);\n    verify(stashClient, times(0)).postTaskOnComment(\"message2\", (long)2222);\n    verify(stashClient, times(0)).postTaskOnComment(\"message1\", (long)1111);\n  }\n\n  @Test\n  public void testPostSonarQubeReportWithNoType() throws Exception {\n    when(stashCommentsReport1.contains(stashCommentMessage1, FILE_PATH_1, 1)).thenReturn(false);\n    when(stashCommentsReport1.contains(stashCommentMessage2, FILE_PATH_1, 2)).thenReturn(false);\n    when(stashCommentsReport2.contains(stashCommentMessage3, FILE_PATH_2, 1)).thenReturn(false);\n\n    when(diffReport.getType(FILE_PATH_1, 1, config.issueVicinityRange())).thenReturn(null);\n    when(diffReport.getType(FILE_PATH_1, 2, config.issueVicinityRange())).thenReturn(STASH_DIFF_TYPE);\n    when(diffReport.getType(FILE_PATH_2, 1, config.issueVicinityRange())).thenReturn(null);\n\n    myFacade.postSonarQubeReport(pr, report, diffReport, stashClient);\n\n    verify(stashClient, times(0)).postCommentLineOnPullRequest(pr,\n                                                               stashCommentMessage1,\n                                                               FILE_PATH_1,\n                                                               1,\n                                                               STASH_DIFF_TYPE);\n    verify(stashClient, times(1)).postCommentLineOnPullRequest(pr,\n                                                               stashCommentMessage2,\n                                                               FILE_PATH_1,\n                                                               2,\n                                                               STASH_DIFF_TYPE);\n    verify(stashClient, times(0)).postCommentLineOnPullRequest(pr,\n                                                               stashCommentMessage3,\n                                                               FILE_PATH_2,\n                                                               1,\n                                                               STASH_DIFF_TYPE);\n  }\n\n  @Test\n  public void testPostSonarQubeReportWithNoSonarQubeIssues() throws Exception {\n    myFacade.postSonarQubeReport(pr, new ArrayList<>(), diffReport, stashClient);\n\n    verify(stashClient, times(0)).postCommentLineOnPullRequest(pr,\n                                                               stashCommentMessage1,\n                                                               FILE_PATH_1,\n                                                               1,\n                                                               STASH_DIFF_TYPE);\n    verify(stashClient, times(0)).postCommentLineOnPullRequest(pr,\n                                                               stashCommentMessage2,\n                                                               FILE_PATH_1,\n                                                               2,\n                                                               STASH_DIFF_TYPE);\n    verify(stashClient, times(0)).postCommentLineOnPullRequest(pr,\n                                                               stashCommentMessage3,\n                                                               FILE_PATH_2,\n                                                               1,\n                                                               STASH_DIFF_TYPE);\n  }\n\n  @Test\n  public void testGetSonarQubeReviewer() throws Exception {\n    when(stashClient.getUser(STASH_USER)).thenReturn(stashUser);\n\n    StashUser reviewer = myFacade.getSonarQubeReviewer(STASH_USER, stashClient);\n    assertEquals(1234, reviewer.getId());\n  }\n\n  @Test\n  public void testGetPullRequestDiffReport() throws Exception {\n    when(stashClient.getPullRequestDiffs(pr)).thenReturn(diffReport);\n\n    StashDiffReport result = myFacade.getPullRequestDiffReport(pr, stashClient);\n\n    assertEquals(1, result.getLine(FILE_PATH_1, 1));\n    assertEquals(2, result.getLine(FILE_PATH_1, 2));\n    assertEquals(1, result.getLine(FILE_PATH_2, 1));\n  }\n\n  @Test\n  public void testResetComments() throws Exception {\n    myFacade.resetComments(pr, diffReport, stashUser, stashClient);\n\n    verify(stashClient, times(3)).deleteTaskOnComment(any(StashTask.class));\n    verify(stashClient, times(3)).deletePullRequestComment(eq(pr), any(StashComment.class));\n  }\n\n  @Test\n  public void testResetCommentsWithNotDeletableTasks() throws Exception {\n    when(comment1.containsPermanentTasks()).thenReturn(true);\n\n    myFacade.resetComments(pr, diffReport, stashUser, stashClient);\n\n    verify(stashClient, times(2)).deleteTaskOnComment(any(StashTask.class));\n    verify(stashClient, times(2)).deletePullRequestComment(eq(pr), any(StashComment.class));\n  }\n\n  @Test\n  public void testResetCommentsWithNoTasks() throws Exception {\n    when(comment1.getTasks()).thenReturn(new ArrayList<StashTask>());\n\n    myFacade.resetComments(pr, diffReport, stashUser, stashClient);\n\n    verify(stashClient, times(2)).deleteTaskOnComment(any(StashTask.class));\n    verify(stashClient, times(3)).deletePullRequestComment(eq(pr), any(StashComment.class));\n  }\n\n  @Test\n  public void testResetCommentsWithDifferentStashUsers() throws Exception {\n    StashUser stashUser2 = mock(StashUser.class);\n    when(stashUser2.getId()).thenReturn((long)4321);\n\n    StashComment comment = mock(StashComment.class);\n    when(comment.getAuthor()).thenReturn(stashUser2);\n\n    ArrayList<StashComment> comments = new ArrayList<>();\n    comments.add(comment);\n\n    when(diffReport.getComments()).thenReturn(comments);\n\n    myFacade.resetComments(pr, diffReport, stashUser, stashClient);\n\n    verify(stashClient, times(0)).deletePullRequestComment(eq(pr), any(StashComment.class));\n  }\n\n  @Test\n  public void testResetCommentsWithoutAnyComments() throws Exception {\n    when(diffReport.getComments()).thenReturn(new ArrayList<StashComment>());\n\n    myFacade.resetComments(pr, diffReport, stashUser, stashClient);\n\n    verify(stashClient, times(0)).deletePullRequestComment(eq(pr), any(StashComment.class));\n  }\n\n\n  @Test\n  public void testApprovePullRequest() throws Exception {\n\n    myFacade.approvePullRequest(pr, stashClient);\n    verify(stashClient, times(1)).approvePullRequest(pr);\n  }\n\n  @Test\n  public void addResetPullRequestApproval() throws Exception {\n\n    myFacade.resetPullRequestApproval(pr, stashClient);\n    verify(stashClient, times(1)).resetPullRequestApproval(pr);\n  }\n\n\n  @Test\n  public void testAddPullRequestReviewer() throws Exception {\n    ArrayList<StashUser> reviewers = new ArrayList<>();\n    StashUser stashUser = mock(StashUser.class);\n    reviewers.add(stashUser);\n\n    StashPullRequest pullRequest = mock(StashPullRequest.class);\n    when(pullRequest.getReviewer(STASH_USER)).thenReturn(null);\n    when(pullRequest.getVersion()).thenReturn((long)1);\n\n    when(stashClient.getPullRequest(pr)).thenReturn(pullRequest);\n    when(stashClient.getUser(STASH_USER)).thenReturn(stashUser);\n\n    myFacade.addPullRequestReviewer(pr, STASH_USER, stashClient);\n\n    verify(stashClient, times(1)).addPullRequestReviewer(pr, 1, reviewers);\n  }\n\n\n  @Test\n  public void testAddPullRequestReviewerWithReviewerAlreadyAdded() throws Exception {\n    ArrayList<StashUser> reviewers = new ArrayList<>();\n    StashUser stashUser = mock(StashUser.class);\n    reviewers.add(stashUser);\n\n    StashPullRequest pullRequest = mock(StashPullRequest.class);\n    when(pullRequest.getReviewer(STASH_USER)).thenReturn(stashUser);\n    when(pullRequest.getVersion()).thenReturn((long)1);\n\n    when(stashClient.getPullRequest(pr)).thenReturn(pullRequest);\n    when(stashClient.getUser(STASH_USER)).thenReturn(stashUser);\n\n    myFacade.addPullRequestReviewer(pr, STASH_USER, stashClient);\n\n    verify(stashClient, times(0)).addPullRequestReviewer(pr, 1, reviewers);\n  }\n\n\n  @Test\n  public void testGetPullRequest() throws Exception {\n\n    doReturn(\"SonarQube\").when(myFacade).getStashProject();\n    doReturn(\"sonar-stash-plugin\").when(myFacade).getStashRepository();\n    doReturn(1337).when(myFacade).getStashPullRequestId();\n\n    assertTrue(myFacade.getPullRequest() instanceof PullRequestRef);\n  }\n\n\n  /* FIXME\n  @Test\n  public void testGetIssuePathWithoutExplicitSourceRootDir() {\n    when(config.getRepositoryRoot()).thenReturn(Optional.empty());\n\n    inputFileCache.putInputFile(\n        \"key\",\n        new DefaultInputFile(\"some/relative/path\").setAbsolutePath(\"/root/some/absolute/path\")\n    );\n    assertEquals(\"some/absolute/path\",\n                 myFacade.getIssuePath(new DefaultIssue().setComponentKey(\"key\")));\n\n\n  }\n\n  @Test\n  public void testGetIssuePathWithExplicitSourceRootDir() {\n    when(config.getRepositoryRoot()).thenReturn(Optional.of(new File(\"/root/some/\")));\n\n    inputFileCache.putInputFile(\n        \"key\",\n        new DefaultInputFile(\"some/relative/path\").setAbsolutePath(\"/root/some/absolute/path\")\n    );\n    assertEquals(\"absolute/path\",\n                 myFacade.getIssuePath(new DefaultIssue().setComponentKey(\"key\")));\n\n\n  }\n  */\n\n  @Test\n  public void testPostCommentPerIssueWithIncludeVicinityIssues() throws Exception {\n    when(config.issueVicinityRange()).thenReturn(10);\n    when(stashCommentsReport1.contains(stashCommentMessage1, FILE_PATH_1, 1)).thenReturn(false);\n    when(stashCommentsReport1.contains(stashCommentMessage2, FILE_PATH_1, 2)).thenReturn(false);\n    when(stashCommentsReport2.contains(stashCommentMessage3, FILE_PATH_2, 1)).thenReturn(false);\n    when(diffReport.getType(FILE_PATH_1, 1, config.issueVicinityRange())).thenReturn(STASH_DIFF_TYPE);\n    when(diffReport.getType(FILE_PATH_1, 2, config.issueVicinityRange())).thenReturn(STASH_DIFF_TYPE);\n    when(diffReport.getType(FILE_PATH_2, 1, config.issueVicinityRange())).thenReturn(STASH_DIFF_TYPE);\n\n    myFacade.postCommentPerIssue(pr, report, diffReport, stashClient);\n\n    verify(stashClient, times(1)).postCommentLineOnPullRequest(pr, stashCommentMessage1, FILE_PATH_1, 1, STASH_DIFF_TYPE);\n    verify(stashClient, times(1)).postCommentLineOnPullRequest(pr, stashCommentMessage2, FILE_PATH_1, 2, STASH_DIFF_TYPE);\n    verify(stashClient, times(1)).postCommentLineOnPullRequest(pr, stashCommentMessage3, FILE_PATH_2, 1, STASH_DIFF_TYPE);\n  }\n}\n"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/StashTest.java",
    "content": "package org.sonar.plugins.stash;\n\nimport org.junit.jupiter.api.extension.RegisterExtension;\n\npublic abstract class StashTest {\n  @RegisterExtension\n  public JavaUtilLoggingCapture logRule = new JavaUtilLoggingCapture();\n}\n"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/TestUtils.java",
    "content": "package org.sonar.plugins.stash;\n\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nimport com.github.tomakehurst.wiremock.WireMockServer;\nimport com.github.tomakehurst.wiremock.client.WireMock;\nimport com.github.tomakehurst.wiremock.stubbing.StubMapping;\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.OutputStream;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\nimport java.nio.file.Path;\nimport java.util.List;\nimport java.util.Map;\nimport org.sonar.api.batch.fs.InputFile;\nimport org.sonar.api.batch.fs.internal.TestInputFileBuilder;\n\npublic class TestUtils {\n  private TestUtils() {}\n\n  public static <T> T notNull(T t) {\n    assertNotNull(t);\n    return t;\n  }\n\n  public static void assertContains(String s, String expected) {\n    assertNotNull(s);\n    assertNotNull(expected);\n    assertTrue(s.contains(expected));\n  }\n\n  // The first request to wiremock may be slow.\n  // We could increase the timeout on our StashClient but then all the timeout test take longer.\n  // So instead we perform a dummy request on each test invocation with a high timeout.\n  // We now have many more request than before, but are faster anyways.\n  public static void primeWireMock(WireMockServer wireMock) throws Exception {\n    StubMapping primingMapping = WireMock.get(WireMock.urlPathEqualTo(\"/\")).build();\n    wireMock.addStubMapping(primingMapping);\n    HttpURLConnection conn = (HttpURLConnection)new URL(\"http://127.0.0.1:\" + wireMock.port()).openConnection();\n    conn.setConnectTimeout(1000);\n    conn.setConnectTimeout(1000);\n    conn.connect();\n    conn.getResponseCode();\n    wireMock.removeStub(primingMapping);\n    wireMock.resetRequests();\n  }\n\n  public static WrappedProcessBuilder createProcess(String prefix, String... command) {\n    ProcessBuilder pb = new ProcessBuilder(command);\n    return new WrappedProcessBuilder(prefix, pb);\n  }\n\n  public static class WrappedProcessBuilder {\n    private final String prefix;\n    private final ProcessBuilder wrapped;\n\n    private WrappedProcessBuilder(String prefix, ProcessBuilder wrapped) {\n      this.prefix = prefix;\n      this.wrapped = wrapped;\n    }\n\n    public WrappedProcessBuilder directory(File directory) {\n      wrapped.directory(directory);\n      return this;\n    }\n\n    public Process start() throws IOException {\n      return new WrappedProcess(prefix, wrapped.start());\n    }\n\n    public List<String> command() {\n      return wrapped.command();\n    }\n\n    public Map<String, String> environment() {\n        return wrapped.environment();\n    }\n  }\n\n  public static class WrappedProcess extends Process {\n    private final Process wrapped;\n    private final ForwarderThread outputLogger;\n    private final ForwarderThread errorLogger;\n\n    private WrappedProcess(String prefix, Process wrapped) {\n      this.wrapped = wrapped;\n      errorLogger = new ForwarderThread(prefix, wrapped.getErrorStream());\n      errorLogger.start();\n      outputLogger = new ForwarderThread(prefix, wrapped.getInputStream());\n      outputLogger.start();\n    }\n\n    @Override\n    public OutputStream getOutputStream() {\n      return wrapped.getOutputStream();\n    }\n\n    @Override\n    public InputStream getInputStream() {\n      return wrapped.getInputStream();\n    }\n\n    @Override\n    public InputStream getErrorStream() {\n      return wrapped.getErrorStream();\n    }\n\n    @Override\n    public int waitFor() throws InterruptedException {\n      int exitCode = wrapped.waitFor();\n      stopLoggers();\n      return exitCode;\n    }\n\n    @Override\n    public int exitValue() {\n      return wrapped.exitValue();\n    }\n\n    @Override\n    public void destroy() {\n        wrapped.destroy();\n    }\n\n    private void stopLoggers() throws InterruptedException {\n      outputLogger.interrupt();\n      errorLogger.interrupt();\n      outputLogger.join();\n      errorLogger.join();\n    }\n  }\n\n  private static class ForwarderThread extends Thread implements AutoCloseable {\n\n    private final String prefix;\n    private final InputStream input;\n\n    private ForwarderThread(String prefix, InputStream input) {\n      this.prefix = \"[\" + prefix + \"] \";\n      this.input = input;\n      setDaemon(true);\n    }\n\n    @Override\n    public void run() {\n      try (BufferedReader lineReader = new BufferedReader(new InputStreamReader(input))) {\n        while (!Thread.interrupted()) {\n          String line = lineReader.readLine();\n          if (line != null) {\n            System.out.println(prefix + line);\n            //logger.info(line);\n          }\n        }\n      } catch (IOException e) {\n        /* ignored */\n      }\n    }\n\n    @Override\n    public void close() throws InterruptedException {\n      interrupt();\n      join();\n    }\n  }\n\n  public static InputFile inputFile(String moduleKey, String path) {\n    return TestInputFileBuilder.create(moduleKey, path).build();\n  }\n\n  public static InputFile inputFile(String moduleKey, Path moduleBaseDir, String path) {\n    return TestInputFileBuilder.create(moduleKey, path).setModuleBaseDir(moduleBaseDir).build();\n  }\n}\n"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/TestWatcherExtension.java",
    "content": "package org.sonar.plugins.stash;\n\nimport org.junit.jupiter.api.extension.AfterEachCallback;\nimport org.junit.jupiter.api.extension.BeforeEachCallback;\nimport org.junit.jupiter.api.extension.ExtensionContext;\n\npublic abstract class TestWatcherExtension implements BeforeEachCallback, AfterEachCallback {\n\n  @Override\n  public void beforeEach(ExtensionContext context) throws Exception {\n    starting();\n  }\n\n  @Override\n  public void afterEach(ExtensionContext context) throws Exception {\n    finished();\n    if (context.getExecutionException().isPresent()) {\n      failed();\n    } else {\n      succeeded();\n    }\n  }\n\n  abstract void starting();\n  abstract void finished();\n  abstract void succeeded();\n  abstract void failed();\n}\n"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/client/ContentTypeTest.java",
    "content": "package org.sonar.plugins.stash.client;\n\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nimport org.junit.jupiter.api.Test;\n\npublic class ContentTypeTest {\n\n  @Test\n  public void testContentType() {\n    ContentType json = new ContentType(\"application\", \"json\", null);\n    assertTrue(json.match(\"application/json\"));\n    assertTrue(json.match(\"application/json;charset=utf-8\"));\n    assertTrue(json.match(\"APPLICATION/JSON\"));\n    assertTrue(json.match(\"ApPlIcAtIoN/jSoN\"));\n\n    assertFalse(json.match(\"\"));\n    assertFalse(json.match(\"/\"));\n    assertFalse(json.match(\";\"));\n    assertFalse(json.match(\"/;\"));\n    assertFalse(json.match(\"foo\"));\n    assertFalse(json.match(\"12!4\"));\n    assertFalse(json.match(\"foo/json\"));\n    assertFalse(json.match(\"application/foo\"));\n    assertFalse(json.match(\"application/foo;charset=utf-8\"));\n  }\n\n  @Test\n  public void testConstructorFailure() {\n    assertThrows(IllegalArgumentException.class, () ->\n        new ContentType(\"application\", \"json\", \"what-is-the-point-if-I-must-be-null?\")\n    );\n  }\n}"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/client/StashClientTest.java",
    "content": "package org.sonar.plugins.stash.client;\r\n\r\nimport static com.github.tomakehurst.wiremock.client.WireMock.aResponse;\r\nimport static com.github.tomakehurst.wiremock.client.WireMock.any;\r\nimport static com.github.tomakehurst.wiremock.client.WireMock.anyUrl;\r\nimport static com.github.tomakehurst.wiremock.client.WireMock.deleteRequestedFor;\r\nimport static com.github.tomakehurst.wiremock.client.WireMock.equalTo;\r\nimport static com.github.tomakehurst.wiremock.client.WireMock.get;\r\nimport static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor;\r\nimport static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor;\r\nimport static com.github.tomakehurst.wiremock.client.WireMock.putRequestedFor;\r\nimport static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo;\r\nimport static com.github.tomakehurst.wiremock.client.WireMock.urlPathMatching;\r\nimport static java.net.HttpURLConnection.HTTP_CREATED;\r\nimport static java.net.HttpURLConnection.HTTP_FORBIDDEN;\r\nimport static java.net.HttpURLConnection.HTTP_MOVED_TEMP;\r\nimport static java.net.HttpURLConnection.HTTP_NOT_IMPLEMENTED;\r\nimport static java.net.HttpURLConnection.HTTP_NO_CONTENT;\r\nimport static java.net.HttpURLConnection.HTTP_OK;\r\nimport static org.junit.jupiter.api.Assertions.assertDoesNotThrow;\r\nimport static org.junit.jupiter.api.Assertions.assertEquals;\r\nimport static org.junit.jupiter.api.Assertions.assertFalse;\r\nimport static org.junit.jupiter.api.Assertions.assertThrows;\r\nimport static org.junit.jupiter.api.Assertions.assertTrue;\r\nimport static org.junit.jupiter.api.Assertions.fail;\r\nimport static org.sonar.plugins.stash.TestUtils.assertContains;\r\nimport static org.sonar.plugins.stash.TestUtils.primeWireMock;\r\n\r\nimport com.github.tomakehurst.wiremock.client.MappingBuilder;\r\nimport com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder;\r\nimport com.github.tomakehurst.wiremock.core.WireMockConfiguration;\r\nimport com.github.tomakehurst.wiremock.matching.EqualToPattern;\r\nimport java.net.HttpURLConnection;\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\nimport org.junit.jupiter.api.BeforeEach;\r\nimport org.junit.jupiter.api.Test;\r\nimport org.junit.jupiter.api.extension.RegisterExtension;\r\nimport org.sonar.plugins.stash.PullRequestRef;\r\nimport org.sonar.plugins.stash.StashPlugin.IssueType;\r\nimport org.sonar.plugins.stash.StashTest;\r\nimport org.sonar.plugins.stash.exceptions.StashClientException;\r\nimport org.sonar.plugins.stash.exceptions.StashReportExtractionException;\r\nimport org.sonar.plugins.stash.fixtures.WireMockExtension;\r\nimport org.sonar.plugins.stash.issue.StashComment;\r\nimport org.sonar.plugins.stash.issue.StashCommentReport;\r\nimport org.sonar.plugins.stash.issue.StashDiffReport;\r\nimport org.sonar.plugins.stash.issue.StashPullRequest;\r\nimport org.sonar.plugins.stash.issue.StashTask;\r\nimport org.sonar.plugins.stash.issue.StashUser;\r\nimport org.sonar.plugins.stash.issue.collector.DiffReportSample;\r\n\r\npublic class StashClientTest extends StashTest {\r\n  private static final int timeout = 800;\r\n  private static final int errorTimeout = timeout + 10;\r\n\r\n  PullRequestRef pr = PullRequestRef.builder()\r\n                                    .setProject(\"Project\")\r\n                                    .setRepository(\"Repository\")\r\n                                    .setPullRequestId(1)\r\n                                    .build();\r\n\r\n  @RegisterExtension\r\n  public WireMockExtension wireMock = new WireMockExtension(WireMockConfiguration.options().dynamicPort());\r\n\r\n  StashClient client;\r\n  StashUser testUser = new StashUser(1, \"userName\", \"userSlug\", \"email\");\r\n\r\n  @BeforeEach\r\n  public void setUp() throws Exception {\r\n    primeWireMock(wireMock);\r\n    client = new StashClient(\"http://127.0.0.1:\" + wireMock.port(),\r\n                             new StashCredentials(\"login@email.com\", \"password\", \"login\"),\r\n                             timeout,\r\n                             \"dummyVersion\");\r\n  }\r\n\r\n  @Test\r\n  public void testPostCommentOnPullRequest() throws Exception {\r\n    wireMock.stubFor(any(anyUrl()).willReturn(aJsonResponse().withStatus(HttpURLConnection.HTTP_CREATED)));\r\n\r\n    assertDoesNotThrow(() ->\r\n        client.postCommentOnPullRequest(pr, \"Report\")\r\n    );\r\n  }\r\n\r\n  @Test\r\n  public void testGetBaseUrl() {\r\n    assertEquals(\"http://127.0.0.1:\" + wireMock.port(), client.getBaseUrl());\r\n  }\r\n\r\n  @Test\r\n  public void testGetLogin() {\r\n    assertEquals(\"login@email.com\", client.getLogin());\r\n  }\r\n\r\n  @Test\r\n  public void testPostCommentOnPullRequestWithWrongHTTPResult() throws Exception {\r\n    addErrorResponse(any(anyUrl()), HTTP_NOT_IMPLEMENTED);\r\n\r\n    try {\r\n      client.postCommentOnPullRequest(pr, \"Report\");\r\n\r\n      fail(\"Wrong HTTP result should raised StashClientException\");\r\n\r\n    } catch (StashClientException e) {\r\n      assertContains(e.getMessage(), String.valueOf(HttpURLConnection.HTTP_NOT_IMPLEMENTED));\r\n      assertContains(e.getMessage(), \"detailed error\");\r\n      assertContains(e.getMessage(), \"seriousException\");\r\n    }\r\n  }\r\n\r\n  @Test\r\n  public void testPostCommentOnPullRequestWithException() throws Exception {\r\n    wireMock.stubFor(any(anyUrl()).willReturn(aJsonResponse().withFixedDelay(errorTimeout)));\r\n    assertThrows(StashClientException.class, () ->\r\n        client.postCommentOnPullRequest(pr, \"Report\")\r\n    );\r\n  }\r\n\r\n  @Test\r\n  public void testGetPullRequestComments() throws Exception {\r\n    String stashJsonComment =\r\n        \"{\\\"values\\\": [{\\\"id\\\":1234, \\\"text\\\":\\\"message\\\", \\\"anchor\\\": {\\\"path\\\":\\\"path\\\", \\\"line\\\":5},\"\r\n        + \"\\\"author\\\": {\\\"id\\\":1, \\\"name\\\":\\\"SonarQube\\\", \\\"slug\\\":\\\"sonarqube\\\", \\\"email\\\":\\\"sq@email.com\\\"}, \\\"version\\\": 0}]}\";\r\n\r\n    wireMock.stubFor(any(anyUrl()).willReturn(aJsonResponse().withBody(stashJsonComment)));\r\n\r\n    StashCommentReport report = client.getPullRequestComments(pr, \"path\");\r\n\r\n    assertTrue(report.contains(\"message\", \"path\", 5));\r\n    assertEquals(1, report.size());\r\n  }\r\n\r\n  @Test\r\n  public void testGetPullRequestCommentsWithoutAuthor() throws Exception {\r\n    String stashJsonComment = \"{\\\"values\\\": [{\\\"id\\\":1234, \\\"text\\\":\\\"message\\\",\"\r\n                              + \"\\\"author\\\": {\\\"id\\\":1, \\\"name\\\":\\\"SonarQube\\\", \\\"slug\\\":\\\"sonarqube\\\", \\\"email\\\":\\\"sq@email.com\\\"}, \\\"version\\\": 0}]}\";\r\n\r\n    wireMock.stubFor(any(anyUrl()).willReturn(aJsonResponse().withBody(stashJsonComment)));\r\n\r\n    assertThrows(StashReportExtractionException.class, () ->\r\n        client.getPullRequestComments(pr, \"path\")\r\n    );\r\n  }\r\n\r\n  @Test\r\n  public void testGetPullRequestCommentsWithNextPage() throws Exception {\r\n    String stashJsonComment1 =\r\n        \"{\\\"values\\\": [{\\\"id\\\":1234, \\\"text\\\":\\\"message1\\\", \\\"anchor\\\": {\\\"path\\\":\\\"path\\\", \\\"line\\\":1},\"\r\n        + \"\\\"author\\\": {\\\"id\\\":1, \\\"name\\\":\\\"SonarQube\\\", \\\"slug\\\":\\\"sonarqube\\\", \\\"email\\\":\\\"sq@email.com\\\"}, \\\"version\\\": 0}], \\\"isLastPage\\\": false, \\\"nextPageStart\\\": 1}\";\r\n\r\n    String stashJsonComment2 =\r\n        \"{\\\"values\\\": [{\\\"id\\\":4321, \\\"text\\\":\\\"message2\\\", \\\"anchor\\\": {\\\"path\\\":\\\"path\\\", \\\"line\\\":2},\"\r\n        + \"\\\"author\\\": {\\\"id\\\":1, \\\"name\\\":\\\"SonarQube\\\", \\\"slug\\\":\\\"sonarqube\\\", \\\"email\\\":\\\"sq@email.com\\\"}, \\\"version\\\": 0}], \\\"isLastPage\\\": true}\";\r\n\r\n    wireMock.stubFor(get(\r\n        urlPathEqualTo(\"/rest/api/1.0/projects/Project/repos/Repository/pull-requests/1/comments\"))\r\n                         .withQueryParam(\"start\", equalTo(String.valueOf(0))).willReturn(\r\n            aJsonResponse().withStatus(HttpURLConnection.HTTP_OK).withBody(stashJsonComment1)\r\n        ));\r\n\r\n    wireMock.stubFor(get(\r\n        urlPathEqualTo(\"/rest/api/1.0/projects/Project/repos/Repository/pull-requests/1/comments\"))\r\n                         .withQueryParam(\"start\", equalTo(String.valueOf(1))).willReturn(\r\n            aJsonResponse().withStatus(HttpURLConnection.HTTP_OK).withBody(stashJsonComment2)\r\n        ));\r\n\r\n    StashCommentReport report = client.getPullRequestComments(pr, \"path\");\r\n    assertTrue(report.contains(\"message1\", \"path\", 1));\r\n    assertTrue(report.contains(\"message2\", \"path\", 2));\r\n    assertEquals(2, report.size());\r\n  }\r\n\r\n  @Test\r\n  public void testGetPullRequestCommentsWithNoNextPage() throws Exception {\r\n    String stashJsonComment1 =\r\n        \"{\\\"values\\\": [{\\\"id\\\":1234, \\\"text\\\":\\\"message1\\\", \\\"anchor\\\": {\\\"path\\\":\\\"path\\\", \\\"line\\\":5},\"\r\n        + \"\\\"author\\\": {\\\"id\\\":1, \\\"name\\\":\\\"SonarQube\\\", \\\"slug\\\":\\\"sonarqube\\\", \\\"email\\\":\\\"sq@email.com\\\"}, \\\"version\\\": 0}], \\\"isLastPage\\\": true, \\\"nextPageStart\\\": 1}\";\r\n\r\n    String stashJsonComment2 =\r\n        \"{\\\"values\\\": [{\\\"id\\\":4321, \\\"text\\\":\\\"message2\\\", \\\"anchor\\\": {\\\"path\\\":\\\"path\\\", \\\"line\\\":10},\"\r\n        + \"\\\"author\\\": {\\\"id\\\":1, \\\"name\\\":\\\"SonarQube\\\", \\\"slug\\\":\\\"sonarqube\\\", \\\"email\\\":\\\"sq@email.com\\\"}, \\\"version\\\": 0}], \\\"isLastPage\\\": true}\";\r\n\r\n    wireMock.stubFor(get(anyUrl()).withQueryParam(\"start\", equalTo(String.valueOf(0))).willReturn(\r\n        aJsonResponse().withStatus(HttpURLConnection.HTTP_OK).withBody(stashJsonComment1)));\r\n\r\n    wireMock.stubFor(get(anyUrl()).withQueryParam(\"start\", equalTo(String.valueOf(1))).willReturn(\r\n        aJsonResponse().withStatus(HttpURLConnection.HTTP_OK).withBody(stashJsonComment2)));\r\n\r\n    StashCommentReport report = client.getPullRequestComments(pr, \"path\");\r\n    assertTrue(report.contains(\"message1\", \"path\", 5));\r\n    assertFalse(report.contains(\"message2\", \"path\", 10));\r\n    assertEquals(1, report.size());\r\n  }\r\n\r\n  @Test\r\n  public void testGetPullRequestCommentsWithWrongHTTPResult() throws Exception {\r\n    wireMock.stubFor(any(anyUrl()).willReturn(aJsonResponse().withStatus(HTTP_FORBIDDEN)));\r\n    assertThrows(StashClientException.class, () ->\r\n        client.getPullRequestComments(pr, \"path\")\r\n    );\r\n  }\r\n\r\n  @Test\r\n  public void testGetPullRequestCommentsWithWrongContentType() throws Exception {\r\n    wireMock.stubFor(any(anyUrl()).willReturn(aXMLResponse().withStatus(HTTP_OK)));\r\n    assertThrows(StashClientException.class, () ->\r\n        client.getPullRequestComments(pr, \"path\")\r\n    );\r\n  }\r\n\r\n  @Test\r\n  public void testGetPullRequestCommentsWithException() throws Exception {\r\n    wireMock.stubFor(any(anyUrl()).willReturn(aJsonResponse().withFixedDelay(errorTimeout)));\r\n    assertThrows(StashClientException.class, () ->\r\n        client.getPullRequestComments(pr, \"path\")\r\n    );\r\n  }\r\n\r\n  @Test\r\n  public void testGetPullRequestDiffs() throws Exception {\r\n    wireMock.stubFor(any(anyUrl()).willReturn(aJsonResponse().withStatus(HTTP_OK)\r\n                                                             .withBody(DiffReportSample.baseReport)));\r\n\r\n    StashDiffReport report = client.getPullRequestDiffs(pr);\r\n    assertEquals(4, report.getDiffs().size());\r\n  }\r\n\r\n  @Test\r\n  public void testGetPullRequestDiffsWithMalformedTasks() throws Exception {\r\n    wireMock.stubFor(any(anyUrl()).willReturn(aJsonResponse().withStatus(HTTP_OK)\r\n                                                             .withBody(DiffReportSample.baseReportWithMalformedTasks)));\r\n\r\n    assertThrows(StashClientException.class, () ->\r\n        client.getPullRequestDiffs(pr)\r\n    );\r\n  }\r\n\r\n  @Test\r\n  public void testGetPullRequestDiffsWithWrongHTTPResult() throws Exception {\r\n    wireMock.stubFor(any(anyUrl()).willReturn(aJsonResponse().withStatus(HTTP_FORBIDDEN)\r\n                                                             .withBody(DiffReportSample.baseReport)));\r\n    assertThrows(StashClientException.class, () ->\r\n        client.getPullRequestDiffs(pr)\r\n    );\r\n  }\r\n\r\n  @Test\r\n  public void testGetPullRequestDiffsWithException() throws Exception {\r\n    wireMock.stubFor(any(anyUrl()).willReturn(aJsonResponse().withFixedDelay(errorTimeout)));\r\n    assertThrows(StashClientException.class, () ->\r\n        client.getPullRequestDiffs(pr)\r\n    );\r\n  }\r\n\r\n  @Test\r\n  public void testPostCommentLineOnPullRequest() throws Exception {\r\n    String stashJsonComment = \"{\\\"id\\\":1234, \\\"text\\\":\\\"message\\\", \\\"anchor\\\": {\\\"path\\\":\\\"path\\\", \\\"line\\\":5},\"\r\n                              + \"\\\"author\\\": {\\\"id\\\":1, \\\"name\\\":\\\"SonarQube\\\", \\\"slug\\\":\\\"sonarqube\\\", \\\"email\\\":\\\"sq@email.com\\\"}, \\\"version\\\": 0}\";\r\n    wireMock.stubFor(any(anyUrl()).willReturn(aJsonResponse().withStatus(HTTP_CREATED).withBody(stashJsonComment)));\r\n\r\n    StashComment comment = client.postCommentLineOnPullRequest(pr, \"message\", \"path\", 5, IssueType.CONTEXT);\r\n    assertEquals(1234, comment.getId());\r\n  }\r\n\r\n  @Test\r\n  public void testPostCommentLineOnPullRequestWithWrongHTTPResult() throws Exception {\r\n    addErrorResponse(any(anyUrl()), HTTP_FORBIDDEN);\r\n\r\n    try {\r\n      client.postCommentLineOnPullRequest(pr, \"message\", \"path\", 5, IssueType.CONTEXT);\r\n      fail(\"Wrong HTTP result should raised StashClientException\");\r\n    } catch (StashClientException e) {\r\n      assertContains(e.getMessage(), \"detailed error\");\r\n      assertContains(e.getMessage(), \"seriousException\");\r\n    }\r\n  }\r\n\r\n  @Test\r\n  public void testPostCommentLineOnPullRequestWithException() throws Exception {\r\n    wireMock.stubFor(any(anyUrl()).willReturn(aJsonResponse().withStatus(HTTP_CREATED).withFixedDelay(errorTimeout)));\r\n    assertThrows(StashClientException.class, () ->\r\n        client.postCommentLineOnPullRequest(pr, \"message\", \"path\", 5, IssueType.CONTEXT)\r\n    );\r\n  }\r\n\r\n  @Test\r\n  public void testGetUser() throws Exception {\r\n    String jsonUser = \"{\\\"name\\\":\\\"SonarQube\\\", \\\"email\\\":\\\"sq@email.com\\\", \\\"id\\\":1, \\\"slug\\\":\\\"sonarqube\\\"}\";\r\n    wireMock.stubFor(any(anyUrl()).willReturn(aJsonResponse().withBody(jsonUser)));\r\n\r\n    StashUser user = client.getUser(\"sonarqube\");\r\n\r\n    assertEquals(1, user.getId());\r\n    assertEquals(\"SonarQube\", user.getName());\r\n    assertEquals(\"sq@email.com\", user.getEmail());\r\n    assertEquals(\"sonarqube\", user.getSlug());\r\n\r\n  }\r\n\r\n  @Test\r\n  public void testGetUserWithWrongHTTPResult() throws Exception {\r\n    wireMock.stubFor(any(anyUrl()).willReturn(aJsonResponse().withStatus(HTTP_FORBIDDEN)));\r\n    assertThrows(StashClientException.class, () ->\r\n        client.getUser(\"sonarqube\")\r\n    );\r\n  }\r\n\r\n  @Test\r\n  public void testDeletePullRequestComment() throws Exception {\r\n    StashComment stashComment = new StashComment(1234, \"message\", \"path\", 42L, testUser, 0);\r\n    wireMock.stubFor(any(anyUrl()).willReturn(aJsonResponse().withStatus(HTTP_NO_CONTENT)));\r\n    client.deletePullRequestComment(pr, stashComment);\r\n    wireMock.verify(deleteRequestedFor(anyUrl()));\r\n  }\r\n\r\n  @Test\r\n  public void testGetPullRequest() throws Exception {\r\n    String jsonPullRequest = \"{\\\"version\\\": 1, \\\"title\\\":\\\"PR-Test\\\", \\\"description\\\":\\\"PR-test\\\", \\\"reviewers\\\": []}\";\r\n    wireMock.stubFor(any(anyUrl()).willReturn(aJsonResponse().withBody(jsonPullRequest)));\r\n\r\n    StashPullRequest pullRequest = client.getPullRequest(pr);\r\n\r\n    assertEquals(1, pullRequest.getId());\r\n    assertEquals(\"Project\", pullRequest.getProject());\r\n    assertEquals(\"Repository\", pullRequest.getRepository());\r\n    assertEquals(1, pullRequest.getVersion());\r\n  }\r\n\r\n\r\n  @Test\r\n  public void testApprovePullRequest() throws Exception {\r\n    wireMock.stubFor(any(anyUrl()).willReturn(aJsonResponse()));\r\n    client.approvePullRequest(pr);\r\n    wireMock.verify(postRequestedFor(anyUrl()));\r\n  }\r\n\r\n\r\n  @Test\r\n  public void testResetPullRequestApproval() throws Exception {\r\n    wireMock.stubFor(any(anyUrl()).willReturn(aJsonResponse()));\r\n    client.resetPullRequestApproval(pr);\r\n    wireMock.verify(deleteRequestedFor(anyUrl()));\r\n  }\r\n\r\n  @Test\r\n  public void testAddPullRequestReviewer() throws Exception {\r\n    wireMock.stubFor(any(anyUrl()).willReturn(aJsonResponse()));\r\n\r\n    List<StashUser> reviewers = new ArrayList<>();\r\n    reviewers.add(testUser);\r\n\r\n    client.addPullRequestReviewer(pr, 1L, reviewers);\r\n    wireMock.verify(putRequestedFor(anyUrl()));\r\n  }\r\n\r\n  @Test\r\n  public void testAddPullRequestReviewerWithNoReviewer() throws Exception {\r\n    wireMock.stubFor(any(anyUrl()).willReturn(aJsonResponse()));\r\n    client.addPullRequestReviewer(pr, 1L, new ArrayList<StashUser>());\r\n    wireMock.verify(putRequestedFor(anyUrl()));\r\n  }\r\n\r\n  @Test\r\n  public void testPostTaskOnComment() throws Exception {\r\n    wireMock.stubFor(any(anyUrl()).willReturn(aJsonResponse().withStatus(HTTP_CREATED)));\r\n    client.postTaskOnComment(\"message\", 1111L);\r\n    wireMock.verify(postRequestedFor(anyUrl()));\r\n  }\r\n\r\n  @Test\r\n  public void testDeleteTaskOnComment() throws Exception {\r\n    wireMock.stubFor(any(anyUrl()).willReturn(aJsonResponse().withStatus(HTTP_NO_CONTENT)));\r\n    StashTask task = new StashTask(1111L, \"some text\", \"some state\", true);\r\n    client.deleteTaskOnComment(task);\r\n    wireMock.verify(deleteRequestedFor(anyUrl()));\r\n  }\r\n\r\n  @Test\r\n  public void testFollowInternalRedirection() throws Exception {\r\n    String jsonUser = \"{\\\"name\\\":\\\"SonarQube\\\", \\\"email\\\":\\\"sq@email.com\\\", \\\"id\\\":1, \\\"slug\\\":\\\"sonarqube\\\"}\";\r\n    wireMock.stubFor(get(anyUrl()).atPriority(2).willReturn(\r\n        aJsonResponse().withStatus(HTTP_MOVED_TEMP).withHeader(\"Location\", \"/foo\")));\r\n    wireMock.stubFor(get(urlPathEqualTo(\"/foo\")).atPriority(1).willReturn(aJsonResponse().withBody(jsonUser)));\r\n    client.getUser(\"does not matter\");\r\n    wireMock.verify(getRequestedFor(urlPathEqualTo(\"/foo\")));\r\n  }\r\n\r\n  @Test\r\n  public void testPullRequestHugePullRequestId() throws Exception {\r\n    // See https://github.com/AmadeusITGroup/sonar-stash/issues/98\r\n    int hugePullRequestId = 1234567890;\r\n\r\n    wireMock.stubFor(any(anyUrl()).willReturn(aJsonResponse()));\r\n\r\n    PullRequestRef pr = PullRequestRef.builder()\r\n                                      .setProject(\"Project\")\r\n                                      .setRepository(\"Repository\")\r\n                                      .setPullRequestId(hugePullRequestId)\r\n                                      .build();\r\n\r\n    client.getPullRequestComments(pr, \"something\");\r\n    wireMock.verify(getRequestedFor(urlPathMatching(\".*/pull-requests/1234567890/comments.*\")));\r\n  }\r\n\r\n  @Test\r\n  public void testClientWithoutCredentials() throws Exception {\r\n    String jsonUser = \"{\\\"name\\\":\\\"SonarQube\\\", \\\"email\\\":\\\"sq@email.com\\\", \\\"id\\\":1, \\\"slug\\\":\\\"sonarqube\\\"}\";\r\n    wireMock.stubFor(any(anyUrl()).willReturn(aJsonResponse().withBody(jsonUser)));\r\n    client = new StashClient(\"http://127.0.0.1:\" + wireMock.port(),\r\n        new StashCredentials(null, null, null),\r\n        timeout,\r\n        \"dummyVersion\");\r\n    client.getUser(\"test\");\r\n    wireMock.verify(getRequestedFor(anyUrl()).withoutHeader(\"Authorization\"));\r\n  }\r\n\r\n  @Test\r\n  public void testClientWithoutPassword() throws Exception {\r\n    String jsonUser = \"{\\\"name\\\":\\\"SonarQube\\\", \\\"email\\\":\\\"sq@email.com\\\", \\\"id\\\":1, \\\"slug\\\":\\\"sonarqube\\\"}\";\r\n    wireMock.stubFor(any(anyUrl()).willReturn(aJsonResponse().withBody(jsonUser)));\r\n    client = new StashClient(\"http://127.0.0.1:\" + wireMock.port(),\r\n        new StashCredentials(\"foo\", null, \"foo\"),\r\n        timeout,\r\n        \"dummyVersion\");\r\n    client.getUser(\"test\");\r\n    wireMock.verify(getRequestedFor(anyUrl()).withHeader(\"Authorization\", new EqualToPattern(\"Basic Zm9vOg==\")));\r\n  }\r\n\r\n  private void addErrorResponse(MappingBuilder mapping, int statusCode) {\r\n    wireMock.stubFor(mapping.willReturn(aJsonResponse()\r\n                                            .withStatus(statusCode)\r\n                                            .withHeader(\"Content-Type\", \"application/json\")\r\n                                            .withBody(\"{\\n\" +\r\n                                                      \"    \\\"errors\\\": [\\n\" +\r\n                                                      \"        {\\n\" +\r\n                                                      \"            \\\"context\\\": null,\\n\" +\r\n                                                      \"            \\\"message\\\": \\\"A detailed error message.\\\",\\n\" +\r\n                                                      \"            \\\"exceptionName\\\": \\\"seriousException\\\"\\n\" +\r\n                                                      \"        }\\n\" +\r\n                                                      \"    ]\\n\" +\r\n                                                      \"}\")\r\n    ));\r\n  }\r\n\r\n  public static ResponseDefinitionBuilder aJsonResponse() {\r\n    return aResponse().withHeader(\"Content-Type\", \"application/json\").withBody(\"{}\");\r\n  }\r\n\r\n  public static ResponseDefinitionBuilder aXMLResponse() {\r\n    return aResponse().withHeader(\"Content-Type\", \"application/xml\")\r\n                      .withBody(\"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?><empty/>\");\r\n  }\r\n}\r\n"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/end2end/EndToEndTest.java",
    "content": "package org.sonar.plugins.stash.end2end;\n\nimport static org.sonar.plugins.stash.TestUtils.notNull;\nimport static org.sonar.plugins.stash.TestUtils.primeWireMock;\n\nimport com.github.tomakehurst.wiremock.core.WireMockConfiguration;\nimport com.google.common.io.Resources;\nimport com.google.gson.JsonObject;\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.function.Consumer;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.extension.RegisterExtension;\nimport org.picocontainer.DefaultPicoContainer;\nimport org.sonar.api.batch.postjob.PostJobContext;\nimport org.sonar.api.batch.postjob.issue.PostJobIssue;\nimport org.sonar.api.batch.sensor.internal.MockAnalysisMode;\nimport org.sonar.api.config.Settings;\nimport org.sonar.api.config.internal.MapSettings;\nimport org.sonar.api.rule.RuleKey;\nimport org.sonar.api.rule.Severity;\nimport org.sonar.plugins.stash.DummyStashProjectBuilder;\nimport org.sonar.plugins.stash.PullRequestRef;\nimport org.sonar.plugins.stash.StashIssueReportingPostJob;\nimport org.sonar.plugins.stash.StashPlugin;\nimport org.sonar.plugins.stash.StashPluginConfiguration;\nimport org.sonar.plugins.stash.StashRequestFacade;\nimport org.sonar.plugins.stash.fixtures.DummyPostJobContext;\nimport org.sonar.plugins.stash.fixtures.DummyPostJobIssue;\nimport org.sonar.plugins.stash.fixtures.DummyServer;\nimport org.sonar.plugins.stash.fixtures.DummyStashServer;\nimport org.sonar.plugins.stash.fixtures.WireMockExtension;\nimport org.sonar.plugins.stash.issue.StashUser;\n\npublic abstract class EndToEndTest {\n  @RegisterExtension\n  public WireMockExtension wireMock = new WireMockExtension(\n      DummyStashServer.extend(WireMockConfiguration.options().dynamicPort()), true);\n\n  @BeforeEach\n  public void setUp() throws Exception {\n    primeWireMock(wireMock);\n  }\n\n  private File repoRoot = new File(\"/invalid/\");\n\n  protected RunResults run(String fixtureName, Consumer<Settings> settingsCustomizer, Collection<PostJobIssue> issues) throws Exception {\n    StashUser user = new StashUser(\n        // has to match data in fixture\n        1,\"some.user\", \"some.user\", \"some.user@example.org\"\n    );\n    PullRequestRef pr = PullRequestRef.builder()\n        .setProject(\"a\")\n        .setRepository(\"b\")\n        .setPullRequestId(42).build();\n    DummyStashServer sqServer = new DummyStashServer(wireMock);\n    sqServer.mockUser(user);\n    sqServer.mockPrDiff(pr, readFixture(fixtureName));\n    sqServer.noCommentsFor(pr);\n    sqServer.expectCommentsUpdateFor(pr);\n\n    Settings settings = new MapSettings();\n    settings.setProperty(StashPlugin.STASH_NOTIFICATION, true);\n    settings.setProperty(StashPlugin.STASH_URL, \"http://127.0.0.1:\" + wireMock.port());\n    settings.setProperty(StashPlugin.STASH_TIMEOUT, 400);\n    settings.setProperty(StashPlugin.STASH_LOGIN, user.getName());\n    settings.setProperty(StashPlugin.STASH_PROJECT, pr.project());\n    settings.setProperty(StashPlugin.STASH_REPOSITORY, pr.repository());\n    settings.setProperty(StashPlugin.STASH_PULL_REQUEST_ID, pr.pullRequestId());\n    settings.setProperty(StashPlugin.STASH_ISSUE_THRESHOLD, Integer.MAX_VALUE);\n    settings.setProperty(StashPlugin.STASH_ISSUE_SEVERITY_THRESHOLD, Severity.MINOR);\n    settings.setProperty(StashPlugin.STASH_REPOSITORY_ROOT, repoRoot.toString());\n    settings.setProperty(StashPlugin.STASH_TASK_SEVERITY_THRESHOLD, Severity.CRITICAL);\n    settingsCustomizer.accept(settings);\n\n    MockAnalysisMode mode = new MockAnalysisMode();\n    mode.setPreviewOrIssue(true);\n\n    DefaultPicoContainer container = new DefaultPicoContainer();\n    container.addComponent(settings);\n    container.addComponent(DummyServer.class);\n    container.addComponent(new DummyStashProjectBuilder(repoRoot));\n    container.addComponent(StashPluginConfiguration.class);\n    container.addComponent(StashRequestFacade.class);\n    container.addComponent(StashIssueReportingPostJob.class);\n\n    PostJobContext context = new DummyPostJobContext(settings, mode, issues);\n    StashIssueReportingPostJob job = notNull(container.getComponent(StashIssueReportingPostJob.class));\n    job.executeThrowing(context);\n\n    RunResults results = new RunResults();\n    results.comments = sqServer.getCreatedComments();\n    return results;\n  }\n\n  protected static class RunResults {\n    public List<JsonObject> comments;\n  }\n\n  private static String readFixture(String name) throws IOException {\n    // https://stackoverflow.com/a/6068228\n    return Resources.toString(\n        Resources.getResource(\"fixtures/\" + name + \".json\"),\n        StandardCharsets.UTF_8\n    );\n  }\n\n  protected PostJobIssue issue(String key, String ruleKey, String module, String moduleSubDir, String path, int line) {\n    return new DummyPostJobIssue(\n        repoRoot.toPath().resolve(moduleSubDir), key, RuleKey.of(\"squid\", ruleKey), module, path, line,\"some message\", org.sonar.api.batch.rule.Severity.MAJOR);\n  }\n}"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/end2end/Issue194.java",
    "content": "package org.sonar.plugins.stash.end2end;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nimport com.google.gson.JsonObject;\nimport java.util.Arrays;\nimport java.util.Optional;\nimport org.junit.jupiter.api.Test;\nimport org.sonar.plugins.stash.StashPlugin;\n\npublic class Issue194 extends EndToEndTest {\n  @Test\n  public void testWithVicinitiyRange() throws Exception {\n    run(0);\n  }\n\n  @Test\n  public void testAfterVicinityRange() throws Exception {\n    run(5);\n  }\n\n  private void run(int vicinityRange) throws Exception {\n    RunResults results = run(\"issue194_stash_diff\",\n        (settings) -> settings.setProperty(StashPlugin.STASH_INCLUDE_VICINITY_RANGE, vicinityRange),\n        Arrays.asList(\n            issue(\"01673981387EDCCDB0\", \"ModifiersOrderCheck\", \"com.gdn.package:module-api-client\", \"aModule-api-client\", \"src/main/java/com/gdn/package/aModule/client/aModuleClient.java\", 56),\n            issue(\"01673981387EDCCDB1\", \"S106\", \"com.gdn.package:module-api-client\", \"aModule-api-client\", \"src/main/java/com/gdn/package/aModule/client/aModuleClient.java\", 109),\n            issue(\"01673981387EDCCDB2\", \"S106\", \"com.gdn.package:module-api-client\", \"aModule-api-client\", \"src/main/java/com/gdn/package/aModule/client/aModuleClient.java\", 120),\n            issue(\"01673981387EDCCDB3\", \"S2583\", \"com.gdn.package:module-api-client\", \"aModule-api-client\", \"src/main/java/com/gdn/package/aModule/client/aModuleClient.java\", 108),\n            issue(\"01673981387EDCCDB4\", \"S1481\", \"com.gdn.package:module-api-client\", \"aModule-api-client\", \"src/main/java/com/gdn/package/aModule/client/aModuleClient.java\", 106),\n            issue(\"01673981387EDCCDB5\", \"S1185\", \"com.gdn.package:module-api-client\", \"aModule-api-client\", \"src/main/java/com/gdn/package/aModule/client/aModuleClient.java\", 207),\n            issue(\"01673981387EDCCDB6\", \"S00117\", \"com.gdn.package:module-api-client\", \"aModule-api-client\", \"src/main/java/com/gdn/package/aModule/client/aModuleClient.java\", 106),\n            issue(\"01673981387EDCCDB7\", \"S00117\", \"com.gdn.package:module-api-client\", \"aModule-api-client\", \"src/main/java/com/gdn/package/aModule/client/aModuleClient.java\", 119)\n        ));\n\n    assertEquals(6, results.comments.size());\n    Optional<JsonObject> comment1 = results.comments.stream().filter((c) -> c.get(\"text\").getAsString().contains(\"S1481\")).findFirst();\n    assertTrue(comment1.isPresent());\n    comment1.ifPresent(c -> {\n      assertNotNull(c);\n      assertEquals(106, c.get(\"anchor\").getAsJsonObject().get(\"line\").getAsLong());\n    });\n    for (JsonObject o: results.comments) {\n      assertEquals(\"TO\", o.get(\"anchor\").getAsJsonObject().get(\"fileType\").getAsString());\n    }\n  }\n}"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/fixtures/DummyIssuePathResolver.java",
    "content": "package org.sonar.plugins.stash.fixtures;\n\nimport org.sonar.api.batch.fs.InputComponent;\nimport org.sonar.api.batch.fs.InputFile;\nimport org.sonar.api.batch.postjob.issue.PostJobIssue;\nimport org.sonar.plugins.stash.IssuePathResolver;\n\npublic class DummyIssuePathResolver implements IssuePathResolver {\n  @Override\n  public String getIssuePath(PostJobIssue issue) {\n    InputComponent ic = issue.inputComponent();\n    if (ic == null) {\n      return null;\n    }\n    return ((InputFile) ic).relativePath();\n  }\n}\n"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/fixtures/DummyPostJobContext.java",
    "content": "package org.sonar.plugins.stash.fixtures;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport org.sonar.api.batch.AnalysisMode;\nimport org.sonar.api.batch.postjob.PostJobContext;\nimport org.sonar.api.batch.postjob.issue.PostJobIssue;\nimport org.sonar.api.config.Configuration;\nimport org.sonar.api.config.Settings;\nimport org.sonar.api.config.internal.ConfigurationBridge;\n\npublic class DummyPostJobContext implements PostJobContext {\n  private final Settings settings;\n  private final AnalysisMode mode;\n  private final Collection<PostJobIssue> issues;\n\n  public DummyPostJobContext(Settings settings, AnalysisMode mode,\n      Collection<PostJobIssue> issues) {\n    this.settings = settings;\n    this.mode = mode;\n    this.issues = issues;\n  }\n\n  @Override\n  public Settings settings() {\n    return settings;\n  }\n\n  @Override\n  public Configuration config() {\n    return new ConfigurationBridge(settings);\n  }\n\n  @Override\n  public AnalysisMode analysisMode() {\n    return mode;\n  }\n\n  @Override\n  public Iterable<PostJobIssue> issues() {\n    return issues;\n  }\n\n  @Override\n  public Iterable<PostJobIssue> resolvedIssues() {\n    return Collections.emptyList();\n  }\n}\n"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/fixtures/DummyPostJobIssue.java",
    "content": "package org.sonar.plugins.stash.fixtures;\n\nimport static org.sonar.plugins.stash.TestUtils.inputFile;\n\nimport java.nio.file.Path;\nimport javax.annotation.CheckForNull;\nimport org.sonar.api.batch.fs.InputComponent;\nimport org.sonar.api.batch.fs.internal.DefaultInputFile;\nimport org.sonar.api.batch.postjob.issue.PostJobIssue;\nimport org.sonar.api.batch.rule.Severity;\nimport org.sonar.api.rule.RuleKey;\n\npublic class DummyPostJobIssue implements PostJobIssue {\n  private final String key;\n  private final RuleKey ruleKey;\n  private final String componentKey;\n  private final Integer line;\n  private final String message;\n  private final Severity severity;\n  private final InputComponent component;\n\n  public DummyPostJobIssue(Path moduleBaseDir, String key, RuleKey ruleKey, String module, String relativePath, Integer line,\n      String message, Severity severity) {\n    this.key = key;\n    this.ruleKey = ruleKey;\n    this.componentKey = module + \":\" + relativePath;\n    this.line = line;\n    this.message = message;\n    this.severity = severity;\n    component = inputFile(componentKey, moduleBaseDir, relativePath);\n  }\n\n  @Override\n  public String key() {\n    return key;\n  }\n\n  @Override\n  public RuleKey ruleKey() {\n    return ruleKey;\n  }\n\n  @Override\n  public String componentKey() {\n    return componentKey;\n  }\n\n  @CheckForNull\n  @Override\n  public InputComponent inputComponent() {\n    return component;\n  }\n\n  @CheckForNull\n  @Override\n  public Integer line() {\n    return line;\n  }\n\n  @CheckForNull\n  @Override\n  public String message() {\n    return message;\n  }\n\n  @Override\n  public Severity severity() {\n    return severity;\n  }\n\n  @Override\n  public boolean isNew() {\n    return true;\n  }\n}\n"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/fixtures/DummyServer.java",
    "content": "package org.sonar.plugins.stash.fixtures;\n\nimport java.io.File;\nimport java.util.Date;\nimport javax.annotation.CheckForNull;\nimport org.sonar.api.platform.Server;\n\npublic class DummyServer extends Server {\n  public DummyServer() {}\n\n  @Override\n  public String getId() {\n    return null;\n  }\n\n  @CheckForNull\n  @Override\n  public String getPermanentServerId() {\n    return null;\n  }\n\n  @Override\n  public String getVersion() {\n    return null;\n  }\n\n  @Override\n  public Date getStartedAt() {\n    return null;\n  }\n\n  @Override\n  public File getRootDir() {\n    return null;\n  }\n\n  @Override\n  public String getContextPath() {\n    return null;\n  }\n\n  @Override\n  public String getPublicRootUrl() {\n    return null;\n  }\n\n  @Override\n  public boolean isDev() {\n    return false;\n  }\n\n  @Override\n  public boolean isSecured() {\n    return false;\n  }\n\n  @Override\n  public String getURL() {\n    return null;\n  }\n}\n"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/fixtures/DummyStashServer.java",
    "content": "package org.sonar.plugins.stash.fixtures;\n\nimport static com.github.tomakehurst.wiremock.client.WireMock.aResponse;\nimport static com.github.tomakehurst.wiremock.client.WireMock.get;\nimport static com.github.tomakehurst.wiremock.client.WireMock.post;\nimport static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\nimport com.github.tomakehurst.wiremock.WireMockServer;\nimport com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder;\nimport com.github.tomakehurst.wiremock.core.WireMockConfiguration;\nimport com.github.tomakehurst.wiremock.http.Request;\nimport com.github.tomakehurst.wiremock.http.Response;\nimport com.google.common.base.Joiner;\nimport com.google.gson.Gson;\nimport com.google.gson.JsonObject;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport org.sonar.plugins.stash.PullRequestRef;\nimport org.sonar.plugins.stash.issue.StashUser;\n\npublic class DummyStashServer {\n  private final WireMockServer wireMock;\n  private final Map<String, StashUser> users = new HashMap<>();\n  private final WireMockResponseCallback responseCallback = new WireMockResponseCallback();\n  private final List<JsonObject> createdComments = new ArrayList<>();\n\n  private int commentId = 0;\n\n  public DummyStashServer(WireMockServer wireMock) {\n    this.wireMock = wireMock;\n  }\n\n  public void mockUser(StashUser user) {\n    users.put(user.getSlug(), user);\n    mockEntity(user, \"users\", user.getSlug());\n  }\n\n  public void mockPrDiff(PullRequestRef pr, String x) {\n    mockResponse(x, \"projects\", pr.project(), \"repos\", pr.repository(), \"pull-requests\", String.valueOf(pr.pullRequestId()), \"diff\");\n  }\n\n  public void noCommentsFor(PullRequestRef pr) {\n    mockResponse(\"{\\\"comments\\\": []}\", \"projects\", pr.project(), \"repos\", pr.repository(), \"pull-requests\", String.valueOf(pr.pullRequestId()), \"comments\");\n  }\n\n  public void expectCommentsUpdateFor(PullRequestRef pr) {\n    wireMock.stubFor(\n        post(urlPathEqualTo(\n            coreApi( \"projects\", pr.project(), \"repos\", pr.repository(), \"pull-requests\", String.valueOf(pr.pullRequestId()), \"comments\")))\n            .willReturn(responseCallback.callback(aJsonResponse().withStatus(201), (request, response, fileSource, parameters) -> {\n                  Gson gson = new Gson();\n                  JsonObject d = gson.fromJson(request.getBodyAsString(), JsonObject.class);\n                  Map<String, Object> result = new HashMap<>();\n                  result.put(\"id\", commentId++);\n                  result.put(\"text\", d.get(\"text\").getAsString());\n                  result.put(\"version\", 1);\n                  result.put(\"author\", getUserFromRequest(request));\n                  createdComments.add(d);\n                  return Response.Builder.like(response)\n                      .but()\n                      .body(gson.toJson(result))\n                      .build();\n                })\n            ));\n  }\n\n  private StashUser getUserFromRequest(Request request) {\n    assertEquals(1, users.size());\n    return users.values().iterator().next();\n  }\n\n  private void mockResponse(String response, String... urlParts) {\n    wireMock.stubFor(\n        get(urlPathEqualTo(\n            coreApi(urlParts)))\n            .willReturn(aJsonResponse().withBody(response)\n            ));\n  }\n\n  private void mockEntity(Object entity, String... urlParts) {\n    wireMock.stubFor(\n        get(urlPathEqualTo(\n            coreApi(urlParts)))\n            .willReturn(aJsonResponse(entity)\n            ));\n  }\n\n  public List<JsonObject> getCreatedComments() {\n    return Collections.unmodifiableList(createdComments);\n  }\n\n  private static String urlPath(String... parts) {\n    return urlPath(true, parts);\n  }\n\n  private static String coreApi(String... parts) {\n    List<String> apiParts = Arrays.asList(\"rest\", \"api\", \"1.0\");\n    ArrayList<String> args = new ArrayList<>(Arrays.asList(parts));\n    args.addAll(0, apiParts);\n    return urlPath(args.toArray(new String[] {}));\n  }\n\n  private static String urlPath(boolean leading, String... parts) {\n    String prefix = \"\";\n    if (leading) {\n      prefix = \"/\";\n    }\n    return prefix + Joiner.on('/').join(parts);\n  }\n\n  public static ResponseDefinitionBuilder aJsonResponse() {\n    return aResponse().withHeader(\"Content-Type\", \"application/json\").withBody(\"{}\");\n  }\n\n  public static ResponseDefinitionBuilder aJsonResponse(Object entity) {\n    Gson gson = new Gson();\n    String body = gson.toJson(entity);\n    return aJsonResponse().withBody(body);\n  }\n\n  public static WireMockConfiguration extend(WireMockConfiguration options) {\n    return options.extensions(WireMockResponseCallback.getExtension());\n  }\n}\n"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/fixtures/MavenSonarFixtures.java",
    "content": "package org.sonar.plugins.stash.fixtures;\n\nimport java.nio.file.FileSystems;\nimport java.nio.file.Path;\n\npublic class MavenSonarFixtures {\n  protected static SonarQube sonarqube = null;\n  protected static SonarScanner sonarScanner = null;\n\n  public synchronized static SonarQube getSonarqube(int port) {\n    if (sonarqube == null) {\n      String outputDir = System.getProperty(\"test.sonarqube.dist.outputdir\");\n      if (outputDir == null) {\n        throw new IllegalArgumentException(\"Location of unpacked SonarQube is not specified\");\n      }\n      String version = System.getProperty(\"test.sonarqube.dist.version\");\n      Path installationDir = FileSystems.getDefault().getPath(outputDir, \"sonarqube-\" + version);\n      sonarqube = new SonarQube(installationDir, version, port);\n    }\n    return sonarqube;\n  }\n\n  public synchronized static SonarScanner getSonarScanner() {\n    if (sonarScanner == null) {\n      String outputDir = System.getProperty(\"test.sonarscanner.dist.outputdir\");\n      if (outputDir == null) {\n        throw new IllegalArgumentException(\"Location of unpacked Sonar Scanner is not specified\");\n      }\n      String version = System.getProperty(\"test.sonarscanner.dist.version\");\n      Path installationDir = FileSystems.getDefault().getPath(outputDir, \"sonar-scanner-\" + version);\n      sonarScanner = new SonarScanner(installationDir);\n    }\n    return sonarScanner;\n  }\n}\n"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/fixtures/SonarQube.java",
    "content": "package org.sonar.plugins.stash.fixtures;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.net.ConnectException;\nimport java.net.HttpURLConnection;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.net.URLEncoder;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.StandardCopyOption;\nimport java.util.Properties;\nimport java.util.concurrent.TimeUnit;\nimport org.awaitility.Awaitility;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.sonar.api.CoreProperties;\nimport org.sonar.plugins.stash.TestUtils;\n\npublic class SonarQube {\n  private final static Logger LOGGER = LoggerFactory.getLogger(SonarQube.class);\n\n  protected Path installDir;\n  protected Process process;\n  protected String version;\n  protected Properties config = new Properties();\n  protected final static String PORT_PROPERTY = \"sonar.web.port\";\n  protected final static String HOST_PROPERTY = \"sonar.web.host\";\n\n  public SonarQube(Path installDir, String version, int port) {\n    this.installDir = installDir;\n    this.version = version;\n    config.setProperty(PORT_PROPERTY, String.valueOf(port));\n    config.setProperty(HOST_PROPERTY, \"127.0.0.1\");\n  }\n\n  public int getPort() {\n    return Integer.parseInt(config.getProperty(PORT_PROPERTY));\n  }\n\n  public String getHost() {\n    return config.getProperty(HOST_PROPERTY);\n  }\n\n  protected File getExecutable() {\n    String os = System.getProperty(\"os.name\");\n    os = os.toLowerCase();\n\n    String arch = System.getProperty(\"os.arch\");\n    if (arch.equals(\"amd64\")) {\n      arch = \"x86-64\";\n    }\n    String binary;\n    if (os.equals(\"windows\")) {\n      binary = \"sonar.bat\";\n    } else {\n      binary = \"sonar.sh\";\n    }\n\n    File exec = installDir.resolve(\"bin\").resolve(os + \"-\" + arch).resolve(binary).toFile();\n    if (!exec.exists()) {\n      throw new IllegalArgumentException();\n    }\n    if (!exec.canExecute()) {\n      throw new IllegalArgumentException();\n    }\n    return exec;\n  }\n\n  public void setUp() {\n    // noop\n  }\n\n  public Properties getConfig() {\n    return config;\n  }\n\n  protected void writeConfig() throws Exception {\n    File configFile = installDir.resolve(\"conf\").resolve(\"sonar.properties\").toFile();\n    configFile.delete();\n    try (OutputStream configStream = new FileOutputStream(configFile)) {\n      config.store(configStream, null);\n    }\n  }\n\n  public void startAsync() throws Exception {\n    writeConfig();\n    process = TestUtils.createProcess(\"sonarqube\", this.getExecutable().toString(), \"start\")\n        .directory(installDir.toFile())\n        .start();\n    if (process.waitFor() != 0) {\n      throw new Exception();\n    }\n  }\n\n  public void stop() throws Exception {\n    TestUtils.createProcess(\"sonarqube\", this.getExecutable().toString(), \"stop\")\n        .directory(installDir.toFile())\n        .start().waitFor();\n  }\n\n  public void installPlugin(File sourceArchive) throws IOException {\n    if (!sourceArchive.exists()) {\n      throw new IllegalArgumentException();\n    }\n\n    Files.copy(sourceArchive.toPath(),\n               installDir.resolve(\"extensions\").resolve(\"plugins\").resolve(sourceArchive.toPath().getFileName()),\n               StandardCopyOption.REPLACE_EXISTING);\n  }\n\n  public void waitForReady() throws MalformedURLException {\n    LOGGER.info(\"Waiting for SonarQube to be available at {}\", getUrl());\n    Awaitility\n        .await(\"SonarQube is ready\")\n        .atMost(3, TimeUnit.MINUTES)\n        .pollInterval(5, TimeUnit.SECONDS)\n        .ignoreExceptionsInstanceOf(ConnectException.class)\n        .until(this::isReady)\n    ;\n  }\n\n  private boolean isReady() throws IOException {\n    HttpURLConnection conn = (HttpURLConnection) getUrl(\"/api/settings/values.protobuf\").openConnection();\n    conn.connect();\n    int code = conn.getResponseCode();\n    return code == 200;\n  }\n\n  private URL getUrl(String file) throws MalformedURLException {\n    return new URL(\"http\", getHost(), getPort(), file);\n  }\n\n  public URL getUrl() throws MalformedURLException {\n    return getUrl(\"/\");\n  }\n\n  public boolean createProject(String key, String name) throws IOException {\n    URL url = new URL(getUrl(),\n                      \"/api/projects/create?\"\n                      + \"key=\" + URLEncoder.encode(key, \"UTF-8\")\n                      + \"&\"\n                      + \"name=\" + URLEncoder.encode(key, \"UTF-8\")\n    );\n    HttpURLConnection conn = (HttpURLConnection)url.openConnection();\n    conn.setRequestMethod(\"POST\");\n    conn.connect();\n    return (conn.getResponseCode() == 200);\n  }\n}\n"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/fixtures/SonarQubeRule.java",
    "content": "package org.sonar.plugins.stash.fixtures;\n\nimport org.junit.jupiter.api.extension.AfterAllCallback;\nimport org.junit.jupiter.api.extension.BeforeAllCallback;\nimport org.junit.jupiter.api.extension.ExtensionContext;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class SonarQubeRule implements BeforeAllCallback, AfterAllCallback {\n  private static final Logger LOGGER = LoggerFactory.getLogger(SonarQubeRule.class);\n\n  private SonarQube sonarqube;\n\n  public SonarQubeRule(SonarQube sonarqube) {\n    this.sonarqube = sonarqube;\n  }\n\n  public void start() throws Exception {\n    sonarqube.startAsync();\n    sonarqube.waitForReady();\n  }\n\n  public SonarQube get() {\n    return sonarqube;\n  }\n\n  @Override\n  public void beforeAll(ExtensionContext context) throws Exception {\n    sonarqube.setUp();\n  }\n\n  @Override\n  public void afterAll(ExtensionContext context) throws Exception {\n    sonarqube.stop();\n  }\n}\n"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/fixtures/SonarScanner.java",
    "content": "package org.sonar.plugins.stash.fixtures;\n\nimport com.google.common.base.Joiner;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.Path;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport org.sonar.plugins.stash.TestUtils;\nimport org.sonar.plugins.stash.TestUtils.WrappedProcessBuilder;\n\npublic class SonarScanner {\n  protected Path installDir;\n\n  public SonarScanner(Path installationDir) {\n    this.installDir = installationDir;\n  }\n\n  protected Path getBinary(String name) {\n    String ext = \"\";\n    if (System.getProperty(\"os.name\").equals(\"Windows\")) {\n      ext = \".bat\";\n    }\n    return installDir.resolve(\"bin\").resolve(name + ext);\n  }\n\n  private void addCliProperty(List<String> cli, String name, Object value) {\n    cli.add(\"-D\" + name + \"=\" + value);\n  }\n\n  public void scan(SonarQube sonarqube,\n                   File baseDir,\n                   String projectKey,\n                   String projectName,\n                   String projectVersion,\n                   Properties properties) throws IOException, InterruptedException {\n    WrappedProcessBuilder pb = TestUtils.createProcess(\"sonar-scanner\", getBinary(\"sonar-scanner\").toString())\n        .directory(installDir.toFile())\n    ;\n\n    Map<String, String> env = pb.environment();\n    env.remove(\"SONAR_TOKEN\");\n    env.remove(\"SONARQUBE_SCANNER_PARAMS\");\n    env.remove(\"SONAR_SCANNER_HOME\");\n\n    List<String> command = pb.command();\n    command.add(\"-e\");\n    addCliProperty(command, \"sonar.projectBaseDir\", baseDir);\n    addCliProperty(command, \"sonar.host.url\", sonarqube.getUrl());\n    addCliProperty(command, \"sonar.projectKey\", projectKey);\n    addCliProperty(command, \"sonar.projectName\", projectName);\n    addCliProperty(command, \"sonar.projectVersion\", projectVersion);\n    addCliProperty(command, \"sonar.scm.provider\", \"git\");\n\n    if (properties != null) {\n      for (String p : properties.stringPropertyNames()) {\n        addCliProperty(command, p, properties.getProperty(p));\n      }\n    }\n    Process process = pb.start();\n    process.waitFor();\n    if (process.exitValue() != 0) {\n      throw new IOException(\"Sonar Scanner failed with \" + process.exitValue());\n    }\n  }\n}\n"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/fixtures/WireMockExtension.java",
    "content": "package org.sonar.plugins.stash.fixtures;\n\nimport com.github.tomakehurst.wiremock.WireMockServer;\nimport com.github.tomakehurst.wiremock.client.VerificationException;\nimport com.github.tomakehurst.wiremock.core.Options;\nimport com.github.tomakehurst.wiremock.verification.LoggedRequest;\nimport com.github.tomakehurst.wiremock.verification.NearMiss;\nimport java.util.List;\nimport org.junit.jupiter.api.extension.AfterEachCallback;\nimport org.junit.jupiter.api.extension.BeforeEachCallback;\nimport org.junit.jupiter.api.extension.ExtensionContext;\n\n// mostly copied from WireMockRule.java\npublic class WireMockExtension extends WireMockServer implements BeforeEachCallback,\n    AfterEachCallback {\n\n  private final boolean failOnUnmatchedRequests;\n\n  public WireMockExtension(Options options) {\n    this(options, true);\n  }\n\n  public WireMockExtension(Options options, boolean failOnUnmatchedRequests) {\n    super(options);\n    this.failOnUnmatchedRequests = failOnUnmatchedRequests;\n  }\n\n  @Override\n  public void beforeEach(ExtensionContext context) throws Exception {\n    start();\n  }\n\n  @Override\n  public void afterEach(ExtensionContext context) throws Exception {\n    checkForUnmatchedRequests();\n  }\n\n  private void checkForUnmatchedRequests() {\n    if (failOnUnmatchedRequests) {\n      List<LoggedRequest> unmatchedRequests = findAllUnmatchedRequests();\n      if (!unmatchedRequests.isEmpty()) {\n        List<NearMiss> nearMisses = findNearMissesForAllUnmatchedRequests();\n        if (nearMisses.isEmpty()) {\n          throw VerificationException.forUnmatchedRequests(unmatchedRequests);\n        } else {\n          throw VerificationException.forUnmatchedNearMisses(nearMisses);\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/fixtures/WireMockResponseCallback.java",
    "content": "package org.sonar.plugins.stash.fixtures;\n\n\nimport com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder;\nimport com.github.tomakehurst.wiremock.common.FileSource;\nimport com.github.tomakehurst.wiremock.extension.Extension;\nimport com.github.tomakehurst.wiremock.extension.Parameters;\nimport com.github.tomakehurst.wiremock.extension.ResponseTransformer;\nimport com.github.tomakehurst.wiremock.http.Request;\nimport com.github.tomakehurst.wiremock.http.Response;\n\npublic class WireMockResponseCallback {\n  public interface ResponseTransformerCallback {\n    Response transform(Request request, Response response, FileSource files, Parameters parameters);\n  }\n\n  private static final String WIREMOCK_EXTENSION_NAME = \"foo\";\n  private static final String CALLBACK_PARAMETER_NAME = \"callback-xxx\";\n\n  private static final Extension transformer = new DummySQResponseTransformer();\n\n  public static Extension getExtension() {\n    return transformer;\n  }\n\n  public ResponseDefinitionBuilder callback(ResponseDefinitionBuilder rdb, ResponseTransformerCallback callback) {\n    return rdb.withTransformer(\n        WIREMOCK_EXTENSION_NAME, CALLBACK_PARAMETER_NAME, new ToStringWrapper(callback)\n    );\n  }\n\n  private static class DummySQResponseTransformer extends ResponseTransformer {\n\n    @Override\n    public String getName() {\n      return WIREMOCK_EXTENSION_NAME;\n    }\n\n    @Override\n    public Response transform(Request request, Response response, FileSource files,\n        Parameters parameters) {\n      if (parameters == null) {\n        return response;\n      }\n      Object callback = parameters.get(CALLBACK_PARAMETER_NAME);\n      if (callback == null) {\n        return response;\n      }\n      if (!(callback instanceof ResponseTransformerCallback)) {\n        throw new IllegalStateException();\n      }\n      return ((ResponseTransformerCallback) callback).transform(request, response, files, parameters);\n    }\n  }\n\n  private static class ToStringWrapper implements ResponseTransformerCallback {\n    private ResponseTransformerCallback wrapped;\n\n    private ToStringWrapper(\n        ResponseTransformerCallback wrapped) {\n\n      this.wrapped = wrapped;\n    }\n\n    public String getLamba() {\n      return wrapped.getClass().getName();\n    }\n\n    @Override\n    public Response transform(Request request, Response response, FileSource files,\n        Parameters parameters) {\n      return wrapped.transform(request, response, files, parameters);\n    }\n  }\n}\n"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/issue/MarkdownPrinterTest.java",
    "content": "package org.sonar.plugins.stash.issue;\r\n\r\nimport static org.junit.jupiter.api.Assertions.assertEquals;\r\nimport static org.sonar.plugins.stash.TestUtils.inputFile;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.Collection;\r\nimport java.util.List;\r\nimport org.junit.jupiter.api.BeforeEach;\r\nimport org.junit.jupiter.api.Test;\r\nimport org.sonar.api.batch.fs.internal.DefaultInputFile;\r\nimport org.sonar.api.batch.postjob.issue.PostJobIssue;\r\nimport org.sonar.api.batch.rule.Severity;\r\nimport org.sonar.api.rule.RuleKey;\r\nimport org.sonar.plugins.stash.DefaultIssue;\r\nimport org.sonar.plugins.stash.fixtures.DummyIssuePathResolver;\r\n\r\npublic class MarkdownPrinterTest {\r\n\r\n  PostJobIssue issue;\r\n\r\n  List<PostJobIssue> report = new ArrayList<>();\r\n\r\n  private static final String SONAR_URL = \"sonarqube/URL\";\r\n  private MarkdownPrinter printer;\r\n  private int issueThreshold;\r\n\r\n  @BeforeEach\r\n  public void setUp() {\r\n    PostJobIssue issueBlocker = new DefaultIssue().setKey(\"key1\")\r\n        .setSeverity(Severity.BLOCKER)\r\n        .setMessage(\"messageBlocker\")\r\n        .setRuleKey(RuleKey.of(\"RepoBlocker\", \"RuleBlocker\"))\r\n        .setInputComponent(inputFile(\"foo1\", \"scripts/file1.example\"))\r\n        .setLine(1);\r\n    PostJobIssue issueCritical = new DefaultIssue().setKey(\"key2\")\r\n        .setSeverity(Severity.CRITICAL)\r\n        .setMessage(\"messageCritical\")\r\n        .setRuleKey(RuleKey.of(\"RepoCritical\", \"RuleCritical\"))\r\n        .setInputComponent(inputFile(\"foo2\", \"scripts/file2.example\"))\r\n        .setLine(1);\r\n    PostJobIssue issueMajor = new DefaultIssue().setKey(\"key3\")\r\n        .setSeverity(Severity.MAJOR)\r\n        .setMessage(\"messageMajor\")\r\n        .setRuleKey(RuleKey.of(\"RepoMajor\", \"RuleMajor\"))\r\n        .setInputComponent(inputFile(\"foo3\", \"scripts/file3.example\"))\r\n        .setLine(1);\r\n    PostJobIssue issueSameFile = new DefaultIssue().setKey(\"key3\")\r\n        .setSeverity(Severity.MAJOR)\r\n        .setMessage(\"messageMajor\")\r\n        .setRuleKey(RuleKey.of(\"RepoMajor\", \"RuleMajor\"))\r\n        .setInputComponent(inputFile(\"foo3\", \"scripts/tests/file3.example\"))\r\n        .setLine(5);\r\n    PostJobIssue issueSameFileHidden = new DefaultIssue().setKey(\"key3\")\r\n        .setSeverity(Severity.MAJOR)\r\n        .setMessage(\"messageMajor\")\r\n        .setRuleKey(RuleKey.of(\"RepoMajor\", \"RuleMajor\"))\r\n        .setInputComponent(inputFile(\"foo3\", \"scripts/file3.example\"))\r\n        .setLine(15);\r\n\r\n    report.add(issueBlocker);\r\n    report.add(issueCritical);\r\n    report.add(issueMajor);\r\n    report.add(issueSameFile);\r\n    report.add(issueSameFileHidden);\r\n\r\n    issue = issueBlocker;\r\n\r\n    issueThreshold = 100;\r\n\r\n    printer = new MarkdownPrinter(issueThreshold, SONAR_URL, 2, new DummyIssuePathResolver());\r\n  }\r\n\r\n  @Test\r\n  public void testPrintIssueMarkdown() {\r\n    assertEquals(\r\n        \"*BLOCKER* - messageBlocker [[RepoBlocker:RuleBlocker](sonarqube/URL/coding_rules#rule_key=RepoBlocker:RuleBlocker)]\",\r\n        printer.printIssueMarkdown(report.get(0))\r\n    );\r\n  }\r\n\r\n  @Test\r\n  public void testPrintIssueMarkdownWithEmptyMessage() {\r\n    assertEquals(\r\n        \"No message\",\r\n        printer.printIssueMarkdown(new DefaultIssue()\r\n            .setMessage(null)\r\n            .setSeverity(Severity.MINOR)\r\n            .setRuleKey(RuleKey.of(\"foo\", \"bar\")))\r\n    );\r\n  }\r\n\r\n  @Test\r\n  public void testPrintIssueNumberBySeverityMarkdown() {\r\n    assertEquals(\r\n        \"| BLOCKER | 1 |\\n\",\r\n        MarkdownPrinter.printIssueNumberBySeverityMarkdown(report, Severity.BLOCKER)\r\n    );\r\n\r\n    assertEquals(\r\n        \"| MAJOR | 3 |\\n\",\r\n        MarkdownPrinter.printIssueNumberBySeverityMarkdown(report, Severity.MAJOR)\r\n    );\r\n\r\n    assertEquals(\r\n        \"| INFO | 0 |\\n\",\r\n        MarkdownPrinter.printIssueNumberBySeverityMarkdown(report, Severity.INFO)\r\n    );\r\n  }\r\n\r\n  @Test\r\n  public void testPrintIssueNumberBySeverityMarkdownWithNoIssues() {\r\n    Collection<PostJobIssue> report = new ArrayList<>();\r\n\r\n    assertEquals(\"| BLOCKER | 0 |\\n\",\r\n        MarkdownPrinter.printIssueNumberBySeverityMarkdown(report, Severity.BLOCKER));\r\n    assertEquals(\"| CRITICAL | 0 |\\n\",\r\n        MarkdownPrinter.printIssueNumberBySeverityMarkdown(report, Severity.CRITICAL));\r\n    assertEquals(\"| MAJOR | 0 |\\n\",\r\n        MarkdownPrinter.printIssueNumberBySeverityMarkdown(report, Severity.MAJOR));\r\n    assertEquals(\"| MINOR | 0 |\\n\",\r\n        MarkdownPrinter.printIssueNumberBySeverityMarkdown(report, Severity.MINOR));\r\n    assertEquals(\"| INFO | 0 |\\n\",\r\n        MarkdownPrinter.printIssueNumberBySeverityMarkdown(report, Severity.INFO));\r\n  }\r\n\r\n  @Test\r\n  public void testPrintReportMarkdown() {\r\n    String issueReportMarkdown = printer.printReportMarkdown(report);\r\n    String reportString = \"## SonarQube analysis Overview\\n\"\r\n        + \"| Total New Issues | 5 |\\n\"\r\n        + \"|-----------------|------|\\n\"\r\n        + \"| BLOCKER | 1 |\\n\"\r\n        + \"| CRITICAL | 1 |\\n\"\r\n        + \"| MAJOR | 3 |\\n\"\r\n        + \"| MINOR | 0 |\\n\"\r\n        + \"| INFO | 0 |\\n\\n\\n\"\r\n        + \"| Issues list |\\n\"\r\n        + \"|-------------|\\n\"\r\n        + \"| *BLOCKER* - messageBlocker [[RepoBlocker:RuleBlocker](sonarqube/URL/coding_rules#rule_key=RepoBlocker:RuleBlocker)] |\\n\"\r\n        + \"| &nbsp;&nbsp; *Files: scripts/file1.example:1* |\\n\"\r\n        + \"| *CRITICAL* - messageCritical [[RepoCritical:RuleCritical](sonarqube/URL/coding_rules#rule_key=RepoCritical:RuleCritical)] |\\n\"\r\n        + \"| &nbsp;&nbsp; *Files: scripts/file2.example:1* |\\n\"\r\n        + \"| *MAJOR* - messageMajor [[RepoMajor:RuleMajor](sonarqube/URL/coding_rules#rule_key=RepoMajor:RuleMajor)] |\\n\"\r\n        + \"| &nbsp;&nbsp; *Files: scripts/file3.example:1, scripts/file3.example:15, ...* |\\n\";\r\n\r\n    assertEquals(reportString, issueReportMarkdown);\r\n  }\r\n\r\n  @Test\r\n  public void testPrintReportMarkdownWithIssueLimitation() {\r\n    printer = new MarkdownPrinter(3, SONAR_URL, 0, new DummyIssuePathResolver());\r\n    String issueReportMarkdown = printer.printReportMarkdown(report);\r\n    String reportString = \"## SonarQube analysis Overview\\n\"\r\n        + \"### Too many issues detected (5/3): Issues cannot be displayed in Diff view.\\n\\n\"\r\n        + \"| Total New Issues | 5 |\\n\"\r\n        + \"|-----------------|------|\\n\"\r\n        + \"| BLOCKER | 1 |\\n\"\r\n        + \"| CRITICAL | 1 |\\n\"\r\n        + \"| MAJOR | 3 |\\n\"\r\n        + \"| MINOR | 0 |\\n\"\r\n        + \"| INFO | 0 |\\n\\n\\n\"\r\n        + \"| Issues list |\\n\"\r\n        + \"|-------------|\\n\"\r\n        + \"| *BLOCKER* - messageBlocker [[RepoBlocker:RuleBlocker](sonarqube/URL/coding_rules#rule_key=RepoBlocker:RuleBlocker)] |\\n\"\r\n        + \"| *CRITICAL* - messageCritical [[RepoCritical:RuleCritical](sonarqube/URL/coding_rules#rule_key=RepoCritical:RuleCritical)] |\\n\"\r\n        + \"| *MAJOR* - messageMajor [[RepoMajor:RuleMajor](sonarqube/URL/coding_rules#rule_key=RepoMajor:RuleMajor)] |\\n\";\r\n\r\n    assertEquals(reportString, issueReportMarkdown);\r\n  }\r\n\r\n  @Test\r\n  public void testPrintReportMarkdownWithFileWideIssues() {\r\n    PostJobIssue issueWithoutLine = new DefaultIssue().setKey(\"key36\")\r\n        .setSeverity(Severity.CRITICAL)\r\n        .setMessage(\"messageCritical\")\r\n        .setRuleKey(RuleKey.of(\"RepoCritical\", \"RuleCritical\"))\r\n        .setInputComponent(inputFile(\"foo2\", \"scripts/file2.example\"))\r\n        .setLine(null);\r\n    report.add(issueWithoutLine);\r\n    printer = new MarkdownPrinter(100, SONAR_URL, 100, new DummyIssuePathResolver());\r\n    String issueReportMarkdown = printer.printReportMarkdown(report);\r\n    String reportString = \"## SonarQube analysis Overview\\n\"\r\n        + \"| Total New Issues | 6 |\\n\"\r\n        + \"|-----------------|------|\\n\"\r\n        + \"| BLOCKER | 1 |\\n\"\r\n        + \"| CRITICAL | 2 |\\n\"\r\n        + \"| MAJOR | 3 |\\n\"\r\n        + \"| MINOR | 0 |\\n\"\r\n        + \"| INFO | 0 |\\n\\n\\n\"\r\n        + \"| Issues list |\\n\"\r\n        + \"|-------------|\\n\"\r\n        + \"| *BLOCKER* - messageBlocker [[RepoBlocker:RuleBlocker](sonarqube/URL/coding_rules#rule_key=RepoBlocker:RuleBlocker)] |\\n\"\r\n        + \"| &nbsp;&nbsp; *Files: scripts/file1.example:1* |\\n\"\r\n        + \"| *CRITICAL* - messageCritical [[RepoCritical:RuleCritical](sonarqube/URL/coding_rules#rule_key=RepoCritical:RuleCritical)] |\\n\"\r\n        + \"| &nbsp;&nbsp; *Files: scripts/file2.example, scripts/file2.example:1* |\\n\"\r\n        + \"| *MAJOR* - messageMajor [[RepoMajor:RuleMajor](sonarqube/URL/coding_rules#rule_key=RepoMajor:RuleMajor)] |\\n\"\r\n        + \"| &nbsp;&nbsp; *Files: scripts/file3.example:1, scripts/file3.example:15, scripts/tests/file3.example:5* |\\n\";\r\n\r\n    assertEquals(reportString, issueReportMarkdown);\r\n\r\n  }\r\n\r\n  @Test\r\n  public void testPrintEmptyReportMarkdown() {\r\n    report = new ArrayList<>();\r\n\r\n    String issueReportMarkdown = printer.printReportMarkdown(report);\r\n    String reportString = \"## SonarQube analysis Overview\\n\"\r\n        + \"### No new issues detected!\\n\\n\";\r\n\r\n    assertEquals(reportString, issueReportMarkdown);\r\n  }\r\n}\r\n"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/issue/StashCommentReportTest.java",
    "content": "package org.sonar.plugins.stash.issue;\r\n\r\nimport org.junit.jupiter.api.BeforeEach;\r\nimport org.junit.jupiter.api.Test;\r\nimport org.mockito.Mock;\r\nimport org.sonar.plugins.stash.StashPlugin.IssueType;\r\n\r\nimport static org.junit.jupiter.api.Assertions.assertEquals;\r\nimport static org.junit.jupiter.api.Assertions.assertFalse;\r\nimport static org.junit.jupiter.api.Assertions.assertTrue;\r\nimport static org.mockito.Mockito.mock;\r\nimport static org.mockito.Mockito.when;\r\n\r\npublic class StashCommentReportTest {\r\n\r\n  @Mock\r\n  StashComment comment1;\r\n\r\n  @Mock\r\n  StashComment comment2;\r\n\r\n  @BeforeEach\r\n  public void setUp() {\r\n    comment1 = mock(StashComment.class);\r\n    when(comment1.getId()).thenReturn((long)123456);\r\n    when(comment1.getLine()).thenReturn((long)1);\r\n    when(comment1.getMessage()).thenReturn(\"message1\");\r\n    when(comment1.getPath()).thenReturn(\"path1\");\r\n\r\n    comment2 = mock(StashComment.class);\r\n    when(comment2.getId()).thenReturn((long)987654);\r\n    when(comment2.getLine()).thenReturn((long)2);\r\n    when(comment2.getMessage()).thenReturn(\"message2\");\r\n    when(comment2.getPath()).thenReturn(\"path2\");\r\n  }\r\n\r\n  @Test\r\n  public void testContains() {\r\n    StashCommentReport report = new StashCommentReport();\r\n    report.add(comment1);\r\n\r\n    assertTrue(report.contains(\"message1\", \"path1\", 1));\r\n\r\n    report = new StashCommentReport();\r\n    report.add(comment2);\r\n\r\n    assertTrue(report.contains(\"message2\", \"path2\", 2));\r\n    assertFalse(report.contains(\"message3\", \"path2\", 2));\r\n  }\r\n\r\n  @Test\r\n  public void testNotContains() {\r\n    StashCommentReport report = new StashCommentReport();\r\n    report.add(comment1);\r\n\r\n    assertFalse(report.contains(\"message\", \"path1\", 1));\r\n    assertFalse(report.contains(\"message1\", \"path\", 1));\r\n    assertFalse(report.contains(\"message1\", \"path1\", (long)2));\r\n  }\r\n\r\n  @Test\r\n  public void testSize() {\r\n    StashCommentReport report = new StashCommentReport();\r\n\r\n    report.add(comment1);\r\n    assertEquals(1, report.size());\r\n\r\n    report.add(comment2);\r\n    assertEquals(2, report.size());\r\n  }\r\n\r\n  @Test\r\n  public void testSizeOfEmptyReport() {\r\n    StashCommentReport report = new StashCommentReport();\r\n    assertEquals(0, report.size());\r\n  }\r\n\r\n  @Test\r\n  public void testAddReport() {\r\n    StashCommentReport report1 = new StashCommentReport();\r\n    report1.add(comment1);\r\n    report1.add(comment2);\r\n\r\n    StashComment comment3 = mock(StashComment.class);\r\n    when(comment3.getLine()).thenReturn((long)3);\r\n    when(comment3.getMessage()).thenReturn(\"message3\");\r\n    when(comment3.getPath()).thenReturn(\"path3\");\r\n\r\n    StashCommentReport report2 = new StashCommentReport();\r\n    report2.add(comment3);\r\n\r\n    report2.add(report1);\r\n    assertEquals(3, report2.size());\r\n\r\n    assertTrue(report2.contains(\"message1\", \"path1\", (long)1));\r\n    assertTrue(report2.contains(\"message2\", \"path2\", (long)2));\r\n    assertTrue(report2.contains(\"message3\", \"path3\", (long)3));\r\n    assertFalse(report2.contains(\"message4\", \"path4\", (long)4));\r\n  }\r\n\r\n  @Test\r\n  public void testAddEmptyReportToNotEmptyReport() {\r\n    StashCommentReport report1 = new StashCommentReport();\r\n    report1.add(comment1);\r\n    report1.add(comment2);\r\n\r\n    StashCommentReport report2 = new StashCommentReport();\r\n    report2.add(report1);\r\n    assertEquals(2, report2.size());\r\n  }\r\n\r\n  @Test\r\n  public void testAddNotEmptyReportToEmptyReport() {\r\n    StashCommentReport report1 = new StashCommentReport();\r\n\r\n    StashCommentReport report2 = new StashCommentReport();\r\n    report2.add(comment1);\r\n\r\n    report1.add(report2);\r\n    assertEquals(1, report1.size());\r\n  }\r\n\r\n  @Test\r\n  public void testAddEmptyReportToEmptyReport() {\r\n    StashCommentReport report1 = new StashCommentReport();\r\n    StashCommentReport report2 = new StashCommentReport();\r\n\r\n    report1.add(report2);\r\n    assertEquals(0, report1.size());\r\n  }\r\n\r\n  @Test\r\n  public void applyDiffReportWithCONTEXT() {\r\n    StashDiff diff = mock(StashDiff.class);\r\n    when(diff.getType()).thenReturn(IssueType.CONTEXT);\r\n    when(diff.getDestination()).thenReturn((long)10);\r\n\r\n    StashDiffReport diffReport = mock(StashDiffReport.class);\r\n    when(diffReport.getDiffByComment(987654)).thenReturn(diff);\r\n\r\n    StashUser stashUser = mock(StashUser.class);\r\n    comment2 = new StashComment(987654, \"message2\", \"path2\", (long)2, stashUser, (long)0);\r\n\r\n    StashCommentReport report = new StashCommentReport();\r\n    report.add(comment1);\r\n    report.add(comment2);\r\n\r\n    report.applyDiffReport(diffReport);\r\n    assertTrue(report.contains(\"message1\", \"path1\", 1));\r\n    assertTrue(report.contains(\"message2\", \"path2\", 10));\r\n  }\r\n\r\n  @Test\r\n  public void applyDiffReportWithADDED() {\r\n    StashDiff diff = mock(StashDiff.class);\r\n    when(diff.getType()).thenReturn(IssueType.ADDED);\r\n    when(diff.getDestination()).thenReturn((long)10);\r\n\r\n    StashDiffReport diffReport = mock(StashDiffReport.class);\r\n    when(diffReport.getDiffByComment(987654)).thenReturn(diff);\r\n\r\n    StashCommentReport report = new StashCommentReport();\r\n    report.add(comment1);\r\n    report.add(comment2);\r\n\r\n    report.applyDiffReport(diffReport);\r\n    assertTrue(report.contains(\"message1\", \"path1\", 1));\r\n    assertTrue(report.contains(\"message2\", \"path2\", 2));\r\n    assertFalse(report.contains(\"message2\", \"path2\", 10));\r\n  }\r\n}\r\n"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/issue/StashCommentTest.java",
    "content": "package org.sonar.plugins.stash.issue;\r\n\r\nimport org.junit.jupiter.api.Test;\r\nimport org.mockito.Mock;\r\n\r\nimport static org.junit.jupiter.api.Assertions.assertEquals;\r\nimport static org.junit.jupiter.api.Assertions.assertFalse;\r\nimport static org.junit.jupiter.api.Assertions.assertNotEquals;\r\nimport static org.junit.jupiter.api.Assertions.assertTrue;\r\nimport static org.mockito.Mockito.mock;\r\nimport static org.mockito.Mockito.when;\r\n\r\npublic class StashCommentTest {\r\n\r\n  @Mock\r\n  StashUser stashUser = mock(StashUser.class);\r\n\r\n  @Test\r\n  public void testGetLine() {\r\n    StashComment comment = new StashComment(1, \"message\", \"path\", (long)123456, stashUser, 0);\r\n    assertEquals(123456, comment.getLine());\r\n  }\r\n\r\n  @Test\r\n  public void testGetNoLine() {\r\n    StashComment comment = new StashComment(1, \"message\", \"path\", null, stashUser, 0);\r\n    assertEquals(0, comment.getLine());\r\n  }\r\n\r\n  @Test\r\n  public void testEquals() {\r\n    StashComment comment1 = new StashComment(1, \"message\", \"path\", (long)1, stashUser, 0);\r\n    StashComment comment2 = new StashComment(2, \"message\", \"path\", (long)1, stashUser, 0);\r\n\r\n    assertNotEquals(comment1, comment2);\r\n\r\n    StashComment comment3 = new StashComment(1, \"message\", \"path\", (long)1, stashUser, 0);\r\n    assertEquals(comment1, comment3);\r\n  }\r\n\r\n  @Test\r\n  public void testAddTask() {\r\n    StashTask task1 = mock(StashTask.class);\r\n    when(task1.getId()).thenReturn((long)1111);\r\n\r\n    StashTask task2 = mock(StashTask.class);\r\n    when(task2.getId()).thenReturn((long)2222);\r\n\r\n    StashComment comment = new StashComment(1, \"message\", \"path\", (long)1, stashUser, 0);\r\n    assertEquals(0, comment.getTasks().size());\r\n\r\n    comment.addTask(task1);\r\n    assertEquals(1, comment.getTasks().size());\r\n    assertEquals(1111, (long) comment.getTasks().get(0).getId());\r\n\r\n    comment.addTask(task2);\r\n    assertEquals(2, comment.getTasks().size());\r\n    assertEquals(1111, (long) comment.getTasks().get(0).getId());\r\n    assertEquals(2222, (long) comment.getTasks().get(1).getId());\r\n  }\r\n\r\n  @Test\r\n  public void testContainsNotDeletableTasks() {\r\n    StashComment comment = new StashComment(1, \"message\", \"path\", (long)1, stashUser, 0);\r\n\r\n    StashTask task1 = mock(StashTask.class);\r\n    when(task1.isDeletable()).thenReturn(true);\r\n    comment.addTask(task1);\r\n\r\n    StashTask task2 = mock(StashTask.class);\r\n    when(task2.isDeletable()).thenReturn(true);\r\n    comment.addTask(task2);\r\n\r\n    assertFalse(comment.containsPermanentTasks());\r\n\r\n    StashTask task3 = mock(StashTask.class);\r\n    when(task3.isDeletable()).thenReturn(false);\r\n    comment.addTask(task3);\r\n\r\n    assertTrue(comment.containsPermanentTasks());\r\n  }\r\n\r\n  @Test\r\n  public void testContainsNotDeletableTasksWithoutTasks() {\r\n    StashComment comment = new StashComment(1, \"message\", \"path\", (long)1, stashUser, 0);\r\n    assertFalse(comment.containsPermanentTasks());\r\n  }\r\n\r\n}\r\n"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/issue/StashDiffReportTest.java",
    "content": "package org.sonar.plugins.stash.issue;\r\n\r\nimport com.google.common.collect.Range;\r\nimport java.util.List;\r\nimport org.junit.jupiter.api.BeforeEach;\r\nimport org.junit.jupiter.api.Test;\r\nimport org.sonar.plugins.stash.StashPlugin.IssueType;\r\n\r\nimport static org.junit.jupiter.api.Assertions.assertEquals;\r\nimport static org.junit.jupiter.api.Assertions.assertNull;\r\nimport static org.mockito.Mockito.mock;\r\nimport static org.mockito.Mockito.when;\r\n\r\npublic class StashDiffReportTest {\r\n\r\n  StashDiff diff1;\r\n  StashDiff diff2;\r\n  StashDiff diff3;\r\n  StashDiff diff4;\r\n  StashDiff diff5;\r\n  StashDiff diff6;\r\n\r\n  StashDiffReport report1 = new StashDiffReport();\r\n  StashDiffReport report2 = new StashDiffReport();\r\n\r\n  private static final String FILE_PATH = \"path/to/diff\";\r\n\r\n  @BeforeEach\r\n  public void setUp() {\r\n    StashComment comment1 = mock(StashComment.class);\r\n    when(comment1.getId()).thenReturn((long)12345);\r\n\r\n    StashComment comment2 = mock(StashComment.class);\r\n    when(comment2.getId()).thenReturn((long)54321);\r\n\r\n    diff1 = new StashDiff(IssueType.CONTEXT, \"path/to/diff1\", (long)10, (long)20);\r\n    diff1.addComment(comment1);\r\n\r\n    diff2 = new StashDiff(IssueType.ADDED, \"path/to/diff2\", (long)20, (long)30);\r\n    diff2.addComment(comment2);\r\n\r\n    diff3 = new StashDiff(IssueType.CONTEXT, \"path/to/diff3\", (long)30, (long)40);\r\n\r\n    report1.add(diff1);\r\n    report1.add(diff2);\r\n    report1.add(diff3);\r\n\r\n    diff4 = new StashDiff(IssueType.CONTEXT, FILE_PATH, (long)10, (long)10);\r\n    diff5 = new StashDiff(IssueType.ADDED, FILE_PATH, (long)11, (long)11);\r\n    diff6 = new StashDiff(IssueType.CONTEXT, FILE_PATH, (long)11, (long)12);\r\n    report2.add(diff4);\r\n    report2.add(diff5);\r\n    report2.add(diff6);\r\n  }\r\n\r\n  @Test\r\n  public void testAdd() {\r\n    StashDiffReport report = new StashDiffReport();\r\n    assertEquals(0, report.getDiffs().size());\r\n\r\n    report.add(diff1);\r\n    assertEquals(1, report.getDiffs().size());\r\n\r\n    StashDiff result1 = report.getDiffs().get(0);\r\n    assertEquals(\"path/to/diff1\", result1.getPath());\r\n    assertEquals(IssueType.CONTEXT, result1.getType());\r\n    assertEquals(10, result1.getSource());\r\n    assertEquals(20, result1.getDestination());\r\n\r\n    report.add(diff2);\r\n    assertEquals(2, report.getDiffs().size());\r\n\r\n    StashDiff result2 = report.getDiffs().get(1);\r\n    assertEquals(\"path/to/diff2\", result2.getPath());\r\n    assertEquals(IssueType.ADDED, result2.getType());\r\n    assertEquals(20, result2.getSource());\r\n    assertEquals(30, result2.getDestination());\r\n  }\r\n\r\n  @Test\r\n  public void testAddReport() {\r\n    assertEquals(3, report1.getDiffs().size());\r\n\r\n    StashDiffReport report = new StashDiffReport();\r\n    assertEquals(0, report.getDiffs().size());\r\n\r\n    report.add(report1);\r\n    assertEquals(3, report.getDiffs().size());\r\n  }\r\n\r\n  @Test\r\n  public void testGetType() {\r\n    assertNull(report1.getType(\"path/to/diff1\", 20, StashDiffReport.VICINITY_RANGE_NONE));\r\n    assertEquals(IssueType.ADDED, report1.getType(\"path/to/diff2\", 30, StashDiffReport.VICINITY_RANGE_NONE));\r\n\r\n    assertNull(report1.getType(\"path/to/diff2\", 20, StashDiffReport.VICINITY_RANGE_NONE));\r\n    assertNull(report1.getType(\"path/to/diff1\", 30, StashDiffReport.VICINITY_RANGE_NONE));\r\n    assertNull(report1.getType(\"path/to/diff4\", 60, StashDiffReport.VICINITY_RANGE_NONE));\r\n  }\r\n\r\n  @Test\r\n  public void testGetTypeWithNoDestination() {\r\n    assertEquals(IssueType.CONTEXT, report1.getType(\"path/to/diff1\", 0, StashDiffReport.VICINITY_RANGE_NONE));\r\n    assertNull(report1.getType(\"path/to/diff\", 0, StashDiffReport.VICINITY_RANGE_NONE));\r\n  }\r\n\r\n  @Test\r\n  public void testGetTypeVicinity() {\r\n    assertEquals(IssueType.CONTEXT, report2.getType(FILE_PATH, 10, 1));\r\n    assertNull(report2.getType(FILE_PATH, 10, StashDiffReport.VICINITY_RANGE_NONE));\r\n    assertEquals(IssueType.ADDED, report2.getType(FILE_PATH, 11, 1));\r\n    assertEquals(IssueType.CONTEXT, report2.getType(FILE_PATH, 12, 1));\r\n    assertNull(report2.getType(FILE_PATH, 12, StashDiffReport.VICINITY_RANGE_NONE));\r\n  }\r\n\r\n  @Test\r\n  public void testGetLine() {\r\n    assertEquals(10, report1.getLine(\"path/to/diff1\", 20));\r\n    assertEquals(30, report1.getLine(\"path/to/diff2\", 30));\r\n    assertEquals(30, report1.getLine(\"path/to/diff3\", 40));\r\n\r\n    assertEquals(0, report1.getLine(\"path/to/diff1\", 50));\r\n  }\r\n\r\n  @Test\r\n  public void testGetDiffByComment() {\r\n    StashDiff diff1 = report1.getDiffByComment(12345);\r\n    assertEquals(\"path/to/diff1\", diff1.getPath());\r\n    assertEquals(IssueType.CONTEXT, diff1.getType());\r\n    assertEquals(10, diff1.getSource());\r\n    assertEquals(20, diff1.getDestination());\r\n\r\n    StashDiff diff2 = report1.getDiffByComment(123456);\r\n    assertNull(diff2);\r\n  }\r\n\r\n  @Test\r\n  public void testGetComments() {\r\n    List<StashComment> comments = report1.getComments();\r\n\r\n    assertEquals(2, comments.size());\r\n    assertEquals(12345, comments.get(0).getId());\r\n    assertEquals(54321, comments.get(1).getId());\r\n  }\r\n\r\n  @Test\r\n  public void testGetCommentsWithoutAnyIssues() {\r\n    StashDiffReport report = new StashDiffReport();\r\n    List<StashComment> comments = report.getComments();\r\n    assertEquals(0, comments.size());\r\n  }\r\n\r\n  @Test\r\n  public void testGetCommentsWithDuplicatedComments() {\r\n    StashComment comment1 = new StashComment((long)12345, \"message\", \"path\", (long)1, mock(StashUser.class), (long)1);\r\n    diff1.addComment(comment1);\r\n\r\n    StashComment comment2 = new StashComment((long)12345, \"message\", \"path\", (long)1, mock(StashUser.class), (long)1);\r\n    diff2.addComment(comment2);\r\n\r\n    StashComment comment3 = new StashComment((long)54321, \"message\", \"path\", (long)1, mock(StashUser.class), (long)1);\r\n    diff3.addComment(comment3);\r\n\r\n    List<StashComment> comments = report1.getComments();\r\n\r\n    assertEquals(2, comments.size());\r\n    assertEquals(12345, comments.get(0).getId());\r\n    assertEquals(54321, comments.get(1).getId());\r\n  }\r\n\r\n  @Test\r\n  public void testVicinitySourceBeforeDestination() {\r\n    // https://github.com/AmadeusITGroup/sonar-stash/issues/189\r\n    final String path = \"some/path\";\r\n    StashDiffReport report = new StashDiffReport();\r\n    report.add(\r\n        new StashDiff(IssueType.REMOVED, path, 165, 132)\r\n    );\r\n    assertEquals(\r\n        IssueType.CONTEXT,\r\n        report.getType(\"some/path\", 164, 2)\r\n    );\r\n  }\r\n}\r\n"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/issue/StashDiffTest.java",
    "content": "package org.sonar.plugins.stash.issue;\r\n\r\nimport org.junit.jupiter.api.BeforeEach;\r\nimport org.junit.jupiter.api.Test;\r\nimport org.sonar.plugins.stash.StashPlugin.IssueType;\r\n\r\nimport static org.junit.jupiter.api.Assertions.assertEquals;\r\nimport static org.junit.jupiter.api.Assertions.assertFalse;\r\nimport static org.junit.jupiter.api.Assertions.assertNotEquals;\r\nimport static org.junit.jupiter.api.Assertions.assertTrue;\r\nimport static org.mockito.Mockito.mock;\r\nimport static org.mockito.Mockito.when;\r\n\r\npublic class StashDiffTest {\r\n\r\n  StashDiff diff1;\r\n  StashDiff diff2;\r\n  StashDiff diff3;\r\n\r\n  @BeforeEach\r\n  public void setUp() {\r\n    StashComment comment1 = mock(StashComment.class);\r\n    when(comment1.getId()).thenReturn((long)12345);\r\n\r\n    StashComment comment2 = mock(StashComment.class);\r\n    when(comment2.getId()).thenReturn((long)54321);\r\n\r\n    diff1 = new StashDiff(IssueType.CONTEXT, \"path/to/diff1\", (long)10, (long)20);\r\n    diff1.addComment(comment1);\r\n\r\n    diff2 = new StashDiff(IssueType.ADDED, \"path/to/diff2\", (long)20, (long)30);\r\n    diff2.addComment(comment2);\r\n\r\n    diff3 = new StashDiff(IssueType.CONTEXT, \"path/to/diff3\", (long)30, (long)40);\r\n  }\r\n\r\n  @Test\r\n  public void testIsTypeOfContext() {\r\n    assertEquals(IssueType.CONTEXT, diff1.getType());\r\n    assertNotEquals(IssueType.CONTEXT, diff2.getType());\r\n  }\r\n\r\n  @Test\r\n  public void testContainsComment() {\r\n    assertTrue(diff1.containsComment(12345));\r\n    assertFalse(diff1.containsComment(54321));\r\n    assertFalse(diff3.containsComment(12345));\r\n  }\r\n\r\n}\r\n"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/issue/StashPullRequestTest.java",
    "content": "package org.sonar.plugins.stash.issue;\r\n\r\nimport static org.junit.jupiter.api.Assertions.assertEquals;\r\nimport static org.junit.jupiter.api.Assertions.assertFalse;\r\nimport static org.junit.jupiter.api.Assertions.assertNull;\r\nimport static org.junit.jupiter.api.Assertions.assertTrue;\r\n\r\nimport org.junit.jupiter.api.BeforeEach;\r\nimport org.junit.jupiter.api.Test;\r\nimport org.sonar.plugins.stash.PullRequestRef;\r\n\r\npublic class StashPullRequestTest {\r\n\r\n  StashPullRequest myPullRequest;\r\n\r\n  StashUser stashUser1;\r\n  StashUser stashUser2;\r\n\r\n  @BeforeEach\r\n  public void setUp() {\r\n    PullRequestRef pr = PullRequestRef.builder()\r\n                                      .setProject(\"Project\")\r\n                                      .setRepository(\"Repository\")\r\n                                      .setPullRequestId(123)\r\n                                      .build();\r\n    myPullRequest = new StashPullRequest(pr);\r\n\r\n    stashUser1 = new StashUser(1, \"SonarQube1\", \"sonarqube1\", \"sq1@email.com\");\r\n    stashUser2 = new StashUser(2, \"SonarQube2\", \"sonarqube2\", \"sq2@email.com\");\r\n  }\r\n\r\n  @Test\r\n  public void testGetProject() {\r\n    assertEquals(\"Project\", myPullRequest.getProject());\r\n  }\r\n\r\n  @Test\r\n  public void testGetRepository() {\r\n    assertEquals(\"Repository\", myPullRequest.getRepository());\r\n  }\r\n\r\n  @Test\r\n  public void testGetId() {\r\n    assertEquals(123, myPullRequest.getId());\r\n  }\r\n\r\n  @Test\r\n  public void testGetVersion() {\r\n    assertEquals(0, myPullRequest.getVersion());\r\n    myPullRequest.setVersion(5);\r\n    assertEquals(5, myPullRequest.getVersion());\r\n  }\r\n\r\n  @Test\r\n  public void testAddReviewer() {\r\n    assertEquals(0, myPullRequest.getReviewers().size());\r\n\r\n    myPullRequest.addReviewer(stashUser1);\r\n\r\n    assertEquals(1, myPullRequest.getReviewers().size());\r\n    assertEquals(1, myPullRequest.getReviewers().get(0).getId());\r\n  }\r\n\r\n  @Test\r\n  public void testAddReviewerTwice() {\r\n    assertEquals(0, myPullRequest.getReviewers().size());\r\n\r\n    myPullRequest.addReviewer(stashUser1);\r\n    myPullRequest.addReviewer(stashUser2);\r\n\r\n    assertEquals(2, myPullRequest.getReviewers().size());\r\n    assertEquals(1, myPullRequest.getReviewers().get(0).getId());\r\n    assertEquals(2, myPullRequest.getReviewers().get(1).getId());\r\n  }\r\n\r\n  @Test\r\n  public void testAddReviewerSameTwice() {\r\n    assertEquals(0, myPullRequest.getReviewers().size());\r\n\r\n    myPullRequest.addReviewer(stashUser1);\r\n    myPullRequest.addReviewer(stashUser1);\r\n\r\n    assertEquals(2, myPullRequest.getReviewers().size());\r\n    assertEquals(1, myPullRequest.getReviewers().get(0).getId());\r\n    assertEquals(1, myPullRequest.getReviewers().get(1).getId());\r\n  }\r\n\r\n  @Test\r\n  public void testGetReviewer() {\r\n    assertEquals(0, myPullRequest.getReviewers().size());\r\n    assertNull(myPullRequest.getReviewer(\"sonarqube1\"));\r\n    assertNull(myPullRequest.getReviewer(\"sonarqube2\"));\r\n\r\n    myPullRequest.addReviewer(stashUser1);\r\n\r\n    assertEquals(1, myPullRequest.getReviewers().size());\r\n    assertEquals(1, myPullRequest.getReviewer(\"sonarqube1\").getId());\r\n    assertNull(myPullRequest.getReviewer(\"sonarqube2\"));\r\n\r\n    myPullRequest.addReviewer(stashUser2);\r\n\r\n    assertEquals(2, myPullRequest.getReviewers().size());\r\n    assertEquals(1, myPullRequest.getReviewer(\"sonarqube1\").getId());\r\n    assertEquals(2, myPullRequest.getReviewer(\"sonarqube2\").getId());\r\n  }\r\n\r\n  @Test\r\n  public void testContainsReviewer() {\r\n    assertEquals(0, myPullRequest.getReviewers().size());\r\n    assertFalse(myPullRequest.containsReviewer(stashUser1));\r\n    assertFalse(myPullRequest.containsReviewer(stashUser2));\r\n\r\n    myPullRequest.addReviewer(stashUser1);\r\n\r\n    assertEquals(1, myPullRequest.getReviewers().size());\r\n    assertTrue(myPullRequest.containsReviewer(stashUser1));\r\n    assertFalse(myPullRequest.containsReviewer(stashUser2));\r\n\r\n    myPullRequest.addReviewer(stashUser2);\r\n\r\n    assertEquals(2, myPullRequest.getReviewers().size());\r\n    assertTrue(myPullRequest.containsReviewer(stashUser1));\r\n    assertTrue(myPullRequest.containsReviewer(stashUser2));\r\n  }\r\n\r\n}"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/issue/StashTaskTest.java",
    "content": "package org.sonar.plugins.stash.issue;\r\n\r\n\r\nimport org.junit.jupiter.api.BeforeEach;\r\nimport org.junit.jupiter.api.Test;\r\n\r\nimport static org.junit.jupiter.api.Assertions.assertEquals;\r\nimport static org.junit.jupiter.api.Assertions.assertTrue;\r\n\r\npublic class StashTaskTest {\r\n\r\n  StashTask myTask;\r\n\r\n  @BeforeEach\r\n  public void setUp() {\r\n    myTask = new StashTask((long)1111, \"Text\", \"State\", true);\r\n  }\r\n\r\n  @Test\r\n  public void testGetId() {\r\n    assertEquals(1111, (long)myTask.getId());\r\n  }\r\n\r\n  @Test\r\n  public void testGetState() {\r\n    assertEquals(\"State\", myTask.getState());\r\n  }\r\n\r\n  @Test\r\n  public void testGetText() {\r\n    assertEquals(\"Text\", myTask.getText());\r\n  }\r\n\r\n  @Test\r\n  public void testIsDeletable() {\r\n    assertTrue(myTask.isDeletable());\r\n  }\r\n}\r\n"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/issue/StashUserTest.java",
    "content": "package org.sonar.plugins.stash.issue;\r\n\r\n\r\nimport org.junit.jupiter.api.BeforeEach;\r\nimport org.junit.jupiter.api.Test;\r\n\r\nimport static org.junit.jupiter.api.Assertions.assertEquals;\r\n\r\npublic class StashUserTest {\r\n\r\n  StashUser myUser;\r\n\r\n  @BeforeEach\r\n  public void setUp() {\r\n    myUser = new StashUser(1, \"SonarQube\", \"sonarqube\", \"sq@email.com\");\r\n  }\r\n\r\n  @Test\r\n  public void testGetId() {\r\n    assertEquals(1, myUser.getId());\r\n  }\r\n\r\n  @Test\r\n  public void testGetName() {\r\n    assertEquals(\"SonarQube\", myUser.getName());\r\n  }\r\n\r\n  @Test\r\n  public void testGetSlug() {\r\n    assertEquals(\"sonarqube\", myUser.getSlug());\r\n  }\r\n\r\n  @Test\r\n  public void testGetEmail() {\r\n    assertEquals(\"sq@email.com\", myUser.getEmail());\r\n  }\r\n\r\n\r\n}\r\n"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/issue/collector/DiffReportSample.java",
    "content": "package org.sonar.plugins.stash.issue.collector;\r\n\r\npublic class DiffReportSample {\r\n\r\n  public static String baseReport = \"{\\\"diffs\\\": [\"\r\n                                    + \"        {\"\r\n                                    + \"            \\\"source\\\": {\"\r\n                                    + \"                \\\"components\\\": [\"\r\n                                    + \"                    \\\"Test.java\\\"\"\r\n                                    + \"                ],\"\r\n                                    + \"                \\\"toString\\\": \\\"stash-plugin/Test.java\\\"\"\r\n                                    + \"            },\"\r\n                                    + \"            \\\"destination\\\": {\"\r\n                                    + \"                \\\"components\\\": [\"\r\n                                    + \"                    \\\"Test.java\\\"\"\r\n                                    + \"               ],\"\r\n                                    + \"               \\\"toString\\\": \\\"stash-plugin/Test.java\\\"\"\r\n                                    + \"            },\"\r\n                                    + \"            \\\"hunks\\\": [\"\r\n                                    + \"                {\"\r\n                                    + \"                    \\\"segments\\\": [\"\r\n                                    + \"                        {\"\r\n                                    + \"                            \\\"type\\\": \\\"CONTEXT\\\",\"\r\n                                    + \"                            \\\"lines\\\": [\"\r\n                                    + \"                                {\"\r\n                                    + \"                                    \\\"source\\\": 10,\"\r\n                                    + \"                                    \\\"destination\\\": 20,\"\r\n                                    + \"                                    \\\"line\\\": \\\"System.out.println(test);\\\",\"\r\n                                    + \"                                    \\\"commentIds\\\": [\"\r\n                                    + \"                                     12345\"\r\n                                    + \"                                    ]\"\r\n                                    + \"                                }\"\r\n                                    + \"                            ],\"\r\n                                    + \"                        },\"\r\n                                    + \"                        {\"\r\n                                    + \"                            \\\"type\\\": \\\"REMOVED\\\",\"\r\n                                    + \"                            \\\"lines\\\": [\"\r\n                                    + \"                                {\"\r\n                                    + \"                                    \\\"source\\\": 20,\"\r\n                                    + \"                                    \\\"destination\\\": 30,\"\r\n                                    + \"                                }\"\r\n                                    + \"                            ],\"\r\n                                    + \"                        },\"\r\n                                    + \"                        {\"\r\n                                    + \"                            \\\"type\\\": \\\"ADDED\\\",\"\r\n                                    + \"                            \\\"lines\\\": [\"\r\n                                    + \"                                {\"\r\n                                    + \"                                    \\\"source\\\": 30,\"\r\n                                    + \"                                    \\\"destination\\\": 40,\"\r\n                                    + \"                                    \\\"line\\\": \\\"System.out.println(test);\\\",\"\r\n                                    + \"                                }\"\r\n                                    + \"                            ],\"\r\n                                    + \"                        },\"\r\n                                    + \"                        {\"\r\n                                    + \"                            \\\"type\\\": \\\"CONTEXT\\\",\"\r\n                                    + \"                            \\\"lines\\\": [\"\r\n                                    + \"                                {\"\r\n                                    + \"                                   \\\"source\\\": 40,\"\r\n                                    + \"                                    \\\"destination\\\": 50,\"\r\n                                    + \"                                    \\\"line\\\": \\\"System.out.println(test);\\\",\"\r\n                                    + \"                                    \\\"commentIds\\\": [\"\r\n                                    + \"                                        54321\"\r\n                                    + \"                                    ]\"\r\n                                    + \"                               }\"\r\n                                    + \"                            ],\"\r\n                                    + \"                        },\"\r\n                                    + \"                        {\"\r\n                                    + \"                            \\\"type\\\": \\\"REMOVED\\\",\"\r\n                                    + \"                            \\\"lines\\\": [\"\r\n                                    + \"                                {\"\r\n                                    + \"                                    \\\"source\\\": 50,\"\r\n                                    + \"                                    \\\"destination\\\": 60,\"\r\n                                    + \"                                    \\\"line\\\": \\\"System.out.println(test);\\\",\"\r\n                                    + \"                                }\"\r\n                                    + \"                            ],\"\r\n                                    + \"                        },\"\r\n                                    + \"                        {\"\r\n                                    + \"                            \\\"type\\\": \\\"ADDED\\\",\"\r\n                                    + \"                            \\\"lines\\\": [\"\r\n                                    + \"                                {\"\r\n                                    + \"                                    \\\"source\\\": 60,\"\r\n                                    + \"                                    \\\"destination\\\": 70,\"\r\n                                    + \"                                    \\\"line\\\": \\\"System.out.println(test);\\\",\"\r\n                                    + \"                                }\"\r\n                                    + \"                            ],\"\r\n                                    + \"                        },\"\r\n                                    + \"                    ],\"\r\n                                    + \"                }\"\r\n                                    + \"            ],\"\r\n                                    + \"            \\\"lineComments\\\": [\"\r\n                                    + \"                {\"\r\n                                    + \"                    \\\"id\\\": 12345,\"\r\n                                    + \"                    \\\"text\\\": \\\"Test comment\\\",\"\r\n                                    + \"                    \\\"version\\\": 1,\"\r\n                                    + \"                    \\\"author\\\": \"\r\n                                    + \"                       {\"\r\n                                    + \"                         \\\"id\\\": 12345,\"\r\n                                    + \"                         \\\"name\\\": \\\"SonarQube\\\",\"\r\n                                    + \"                         \\\"slug\\\": \\\"sonarqube\\\",\"\r\n                                    + \"                         \\\"email\\\": \\\"sq@email.com\\\",\"\r\n                                    + \"                       },\"\r\n                                    + \"                     \\\"tasks\\\": [\"\r\n                                    + \"                       {\"\r\n                                    + \"                         \\\"id\\\": 12345,\"\r\n                                    + \"                         \\\"text\\\": \\\"Complete the task associated to this TODO comment.\\\",\"\r\n                                    + \"                         \\\"state\\\": \\\"OPENED\\\",\"\r\n                                    + \"                         \\\"permittedOperations\\\": {\"\r\n                                    + \"                             \\\"deletable\\\": true\"\r\n                                    + \"                         }\"\r\n                                    + \"                       },\"\r\n                                    + \"                       {\"\r\n                                    + \"                         \\\"id\\\": 54321,\"\r\n                                    + \"                         \\\"text\\\": \\\"Complete the task associated to this TODO comment.\\\",\"\r\n                                    + \"                         \\\"state\\\": \\\"OPENED\\\",\"\r\n                                    + \"                         \\\"permittedOperations\\\": {\"\r\n                                    + \"                             \\\"deletable\\\": true\"\r\n                                    + \"                         }\"\r\n                                    + \"                       }]\"\r\n                                    + \"                },\"\r\n                                    + \"                {\"\r\n                                    + \"                    \\\"id\\\": 54321,\"\r\n                                    + \"                    \\\"text\\\": \\\"Test comment 2\\\",\"\r\n                                    + \"                    \\\"version\\\": 1,\"\r\n                                    + \"                    \\\"author\\\": \"\r\n                                    + \"                       {\"\r\n                                    + \"                         \\\"id\\\": 54321,\"\r\n                                    + \"                         \\\"name\\\": \\\"SonarQube2\\\",\"\r\n                                    + \"                         \\\"slug\\\": \\\"sonarqube2\\\",\"\r\n                                    + \"                         \\\"email\\\": \\\"sq2@email.com\\\",\"\r\n                                    + \"                       },\"\r\n                                    + \"                }\"\r\n                                    + \"            ]\"\r\n                                    + \"        }\"\r\n                                    + \"    ]\"\r\n                                    + \"}\";\r\n\r\n  public static String baseReportWithMalformedTasks = \"{\\\"diffs\\\": [\"\r\n                                                      + \"        {\"\r\n                                                      + \"            \\\"source\\\": {\"\r\n                                                      + \"                \\\"components\\\": [\"\r\n                                                      + \"                    \\\"Test.java\\\"\"\r\n                                                      + \"                ],\"\r\n                                                      + \"                \\\"toString\\\": \\\"stash-plugin/Test.java\\\"\"\r\n                                                      + \"            },\"\r\n                                                      + \"            \\\"destination\\\": {\"\r\n                                                      + \"                \\\"components\\\": [\"\r\n                                                      + \"                    \\\"Test.java\\\"\"\r\n                                                      + \"               ],\"\r\n                                                      + \"               \\\"toString\\\": \\\"stash-plugin/Test.java\\\"\"\r\n                                                      + \"            },\"\r\n                                                      + \"            \\\"hunks\\\": [\"\r\n                                                      + \"                {\"\r\n                                                      + \"                    \\\"segments\\\": [\"\r\n                                                      + \"                        {\"\r\n                                                      + \"                            \\\"type\\\": \\\"CONTEXT\\\",\"\r\n                                                      + \"                            \\\"lines\\\": [\"\r\n                                                      + \"                                {\"\r\n                                                      + \"                                    \\\"source\\\": 10,\"\r\n                                                      + \"                                    \\\"destination\\\": 20,\"\r\n                                                      + \"                                    \\\"line\\\": \\\"System.out.println(test);\\\",\"\r\n                                                      + \"                                    \\\"commentIds\\\": [\"\r\n                                                      + \"                                     12345\"\r\n                                                      + \"                                    ]\"\r\n                                                      + \"                                }\"\r\n                                                      + \"                            ],\"\r\n                                                      + \"                        },\"\r\n                                                      + \"                        {\"\r\n                                                      + \"                            \\\"type\\\": \\\"REMOVED\\\",\"\r\n                                                      + \"                            \\\"lines\\\": [\"\r\n                                                      + \"                                {\"\r\n                                                      + \"                                    \\\"source\\\": 20,\"\r\n                                                      + \"                                    \\\"destination\\\": 30,\"\r\n                                                      + \"                                }\"\r\n                                                      + \"                            ],\"\r\n                                                      + \"                        },\"\r\n                                                      + \"                        {\"\r\n                                                      + \"                            \\\"type\\\": \\\"ADDED\\\",\"\r\n                                                      + \"                            \\\"lines\\\": [\"\r\n                                                      + \"                                {\"\r\n                                                      + \"                                    \\\"source\\\": 30,\"\r\n                                                      + \"                                    \\\"destination\\\": 40,\"\r\n                                                      + \"                                    \\\"line\\\": \\\"System.out.println(test);\\\",\"\r\n                                                      + \"                                }\"\r\n                                                      + \"                            ],\"\r\n                                                      + \"                        },\"\r\n                                                      + \"                        {\"\r\n                                                      + \"                            \\\"type\\\": \\\"CONTEXT\\\",\"\r\n                                                      + \"                            \\\"lines\\\": [\"\r\n                                                      + \"                                {\"\r\n                                                      + \"                                   \\\"source\\\": 40,\"\r\n                                                      + \"                                    \\\"destination\\\": 50,\"\r\n                                                      + \"                                    \\\"line\\\": \\\"System.out.println(test);\\\",\"\r\n                                                      + \"                                    \\\"commentIds\\\": [\"\r\n                                                      + \"                                        54321\"\r\n                                                      + \"                                    ]\"\r\n                                                      + \"                               }\"\r\n                                                      + \"                            ],\"\r\n                                                      + \"                        },\"\r\n                                                      + \"                        {\"\r\n                                                      + \"                            \\\"type\\\": \\\"REMOVED\\\",\"\r\n                                                      + \"                            \\\"lines\\\": [\"\r\n                                                      + \"                                {\"\r\n                                                      + \"                                    \\\"source\\\": 50,\"\r\n                                                      + \"                                    \\\"destination\\\": 60,\"\r\n                                                      + \"                                    \\\"line\\\": \\\"System.out.println(test);\\\",\"\r\n                                                      + \"                                }\"\r\n                                                      + \"                            ],\"\r\n                                                      + \"                        },\"\r\n                                                      + \"                        {\"\r\n                                                      + \"                            \\\"type\\\": \\\"ADDED\\\",\"\r\n                                                      + \"                            \\\"lines\\\": [\"\r\n                                                      + \"                                {\"\r\n                                                      + \"                                    \\\"source\\\": 60,\"\r\n                                                      + \"                                    \\\"destination\\\": 70,\"\r\n                                                      + \"                                    \\\"line\\\": \\\"System.out.println(test);\\\",\"\r\n                                                      + \"                                }\"\r\n                                                      + \"                            ],\"\r\n                                                      + \"                        },\"\r\n                                                      + \"                    ],\"\r\n                                                      + \"                }\"\r\n                                                      + \"            ],\"\r\n                                                      + \"            \\\"lineComments\\\": [\"\r\n                                                      + \"                {\"\r\n                                                      + \"                    \\\"id\\\": 12345,\"\r\n                                                      + \"                    \\\"text\\\": \\\"Test comment\\\",\"\r\n                                                      + \"                    \\\"version\\\": 1,\"\r\n                                                      + \"                    \\\"author\\\": \"\r\n                                                      + \"                       {\"\r\n                                                      + \"                         \\\"id\\\": 12345,\"\r\n                                                      + \"                       },\"\r\n                                                      + \"                     \\\"tasks\\\": [\"\r\n                                                      + \"                       {\"\r\n                                                      + \"                         \\\"id\\\": 12345\"\r\n                                                      + \"                         \\\"text\\\": \\\"Complete the task associated to this TODO comment.\\\"\"\r\n                                                      + \"                         \\\"state\\\": \\\"OPENED\\\",\"\r\n                                                      + \"                       },\"\r\n                                                      + \"                         \\\"permittedOperations\\\" {\"\r\n                                                      + \"                             \\\"deletable\\\": true\"\r\n                                                      + \"                         }\"\r\n                                                      + \"                       }]\"\r\n                                                      + \"                },\"\r\n                                                      + \"                {\"\r\n                                                      + \"                    \\\"id\\\": 54321,\"\r\n                                                      + \"                    \\\"text\\\": \\\"Test comment 2\\\",\"\r\n                                                      + \"                    \\\"version\\\": 1,\"\r\n                                                      + \"                    \\\"author\\\": \"\r\n                                                      + \"                       {\"\r\n                                                      + \"                         \\\"id\\\": 54321,\"\r\n                                                      + \"                       },\"\r\n                                                      + \"                }\"\r\n                                                      + \"            ]\"\r\n                                                      + \"        }\"\r\n                                                      + \"    ]\"\r\n                                                      + \"}\";\r\n\r\n  public static String baseReportWithFileComments = \"{\\\"diffs\\\": [\"\r\n                                                    + \"        {\"\r\n                                                    + \"            \\\"source\\\": {\"\r\n                                                    + \"                \\\"components\\\": [\"\r\n                                                    + \"                    \\\"Test.java\\\"\"\r\n                                                    + \"                ],\"\r\n                                                    + \"                \\\"toString\\\": \\\"stash-plugin/Test.java\\\"\"\r\n                                                    + \"            },\"\r\n                                                    + \"            \\\"destination\\\": {\"\r\n                                                    + \"                \\\"components\\\": [\"\r\n                                                    + \"                    \\\"Test.java\\\"\"\r\n                                                    + \"               ],\"\r\n                                                    + \"               \\\"toString\\\": \\\"stash-plugin/Test.java\\\"\"\r\n                                                    + \"            },\"\r\n                                                    + \"            \\\"hunks\\\": [\"\r\n                                                    + \"                {\"\r\n                                                    + \"                    \\\"segments\\\": [\"\r\n                                                    + \"                        {\"\r\n                                                    + \"                            \\\"type\\\": \\\"CONTEXT\\\",\"\r\n                                                    + \"                            \\\"lines\\\": [\"\r\n                                                    + \"                                {\"\r\n                                                    + \"                                    \\\"source\\\": 10,\"\r\n                                                    + \"                                    \\\"destination\\\": 20,\"\r\n                                                    + \"                                    \\\"line\\\": \\\"System.out.println(test);\\\",\"\r\n                                                    + \"                                    \\\"commentIds\\\": [\"\r\n                                                    + \"                                     12345\"\r\n                                                    + \"                                    ]\"\r\n                                                    + \"                                }\"\r\n                                                    + \"                            ],\"\r\n                                                    + \"                        },\"\r\n                                                    + \"                        {\"\r\n                                                    + \"                            \\\"type\\\": \\\"REMOVED\\\",\"\r\n                                                    + \"                            \\\"lines\\\": [\"\r\n                                                    + \"                                {\"\r\n                                                    + \"                                    \\\"source\\\": 20,\"\r\n                                                    + \"                                    \\\"destination\\\": 30,\"\r\n                                                    + \"                                }\"\r\n                                                    + \"                            ],\"\r\n                                                    + \"                        },\"\r\n                                                    + \"                        {\"\r\n                                                    + \"                            \\\"type\\\": \\\"ADDED\\\",\"\r\n                                                    + \"                            \\\"lines\\\": [\"\r\n                                                    + \"                                {\"\r\n                                                    + \"                                    \\\"source\\\": 30,\"\r\n                                                    + \"                                    \\\"destination\\\": 40,\"\r\n                                                    + \"                                    \\\"line\\\": \\\"System.out.println(test);\\\",\"\r\n                                                    + \"                                }\"\r\n                                                    + \"                            ],\"\r\n                                                    + \"                        },\"\r\n                                                    + \"                        {\"\r\n                                                    + \"                            \\\"type\\\": \\\"CONTEXT\\\",\"\r\n                                                    + \"                            \\\"lines\\\": [\"\r\n                                                    + \"                                {\"\r\n                                                    + \"                                   \\\"source\\\": 40,\"\r\n                                                    + \"                                    \\\"destination\\\": 50,\"\r\n                                                    + \"                                    \\\"line\\\": \\\"System.out.println(test);\\\",\"\r\n                                                    + \"                                    \\\"commentIds\\\": [\"\r\n                                                    + \"                                        54321\"\r\n                                                    + \"                                    ]\"\r\n                                                    + \"                               }\"\r\n                                                    + \"                            ],\"\r\n                                                    + \"                        },\"\r\n                                                    + \"                        {\"\r\n                                                    + \"                            \\\"type\\\": \\\"REMOVED\\\",\"\r\n                                                    + \"                            \\\"lines\\\": [\"\r\n                                                    + \"                                {\"\r\n                                                    + \"                                    \\\"source\\\": 50,\"\r\n                                                    + \"                                    \\\"destination\\\": 60,\"\r\n                                                    + \"                                    \\\"line\\\": \\\"System.out.println(test);\\\",\"\r\n                                                    + \"                                }\"\r\n                                                    + \"                            ],\"\r\n                                                    + \"                        },\"\r\n                                                    + \"                        {\"\r\n                                                    + \"                            \\\"type\\\": \\\"ADDED\\\",\"\r\n                                                    + \"                            \\\"lines\\\": [\"\r\n                                                    + \"                                {\"\r\n                                                    + \"                                    \\\"source\\\": 60,\"\r\n                                                    + \"                                    \\\"destination\\\": 70,\"\r\n                                                    + \"                                    \\\"line\\\": \\\"System.out.println(test);\\\",\"\r\n                                                    + \"                                }\"\r\n                                                    + \"                            ],\"\r\n                                                    + \"                        },\"\r\n                                                    + \"                    ],\"\r\n                                                    + \"                }\"\r\n                                                    + \"            ],\"\r\n                                                    + \"            \\\"lineComments\\\": [\"\r\n                                                    + \"                {\"\r\n                                                    + \"                    \\\"id\\\": 12345,\"\r\n                                                    + \"                    \\\"text\\\": \\\"Test comment\\\",\"\r\n                                                    + \"                    \\\"version\\\": 1,\"\r\n                                                    + \"                    \\\"author\\\": \"\r\n                                                    + \"                       {\"\r\n                                                    + \"                         \\\"id\\\": 12345,\"\r\n                                                    + \"                         \\\"name\\\": \\\"SonarQube\\\",\"\r\n                                                    + \"                         \\\"slug\\\": \\\"sonarqube\\\",\"\r\n                                                    + \"                         \\\"email\\\": \\\"sq@email.com\\\",\"\r\n                                                    + \"                       },\"\r\n                                                    + \"                },\"\r\n                                                    + \"                {\"\r\n                                                    + \"                    \\\"id\\\": 54321,\"\r\n                                                    + \"                    \\\"text\\\": \\\"Test comment 2\\\",\"\r\n                                                    + \"                    \\\"version\\\": 1,\"\r\n                                                    + \"                    \\\"author\\\": \"\r\n                                                    + \"                       {\"\r\n                                                    + \"                         \\\"id\\\": 54321,\"\r\n                                                    + \"                         \\\"name\\\": \\\"SonarQube2\\\",\"\r\n                                                    + \"                         \\\"slug\\\": \\\"sonarqube2\\\",\"\r\n                                                    + \"                         \\\"email\\\": \\\"sq2@email.com\\\",\"\r\n                                                    + \"                       },\"\r\n                                                    + \"                }\"\r\n                                                    + \"            ]\"\r\n                                                    + \"            \\\"fileComments\\\": [\"\r\n                                                    + \"                {\"\r\n                                                    + \"                    \\\"id\\\": 123456,\"\r\n                                                    + \"                    \\\"text\\\": \\\"Test File comment\\\",\"\r\n                                                    + \"                    \\\"version\\\": 1,\"\r\n                                                    + \"                    \\\"author\\\": \"\r\n                                                    + \"                       {\"\r\n                                                    + \"                         \\\"id\\\": 12345,\"\r\n                                                    + \"                         \\\"name\\\": \\\"SonarQube\\\",\"\r\n                                                    + \"                         \\\"slug\\\": \\\"sonarqube\\\",\"\r\n                                                    + \"                         \\\"email\\\": \\\"sq@email.com\\\",\"\r\n                                                    + \"                       },\"\r\n                                                    + \"                },\"\r\n                                                    + \"                {\"\r\n                                                    + \"                    \\\"id\\\": 654321,\"\r\n                                                    + \"                    \\\"text\\\": \\\"Test File comment 2\\\",\"\r\n                                                    + \"                    \\\"version\\\": 1,\"\r\n                                                    + \"                    \\\"author\\\": \"\r\n                                                    + \"                       {\"\r\n                                                    + \"                         \\\"id\\\": 54321,\"\r\n                                                    + \"                         \\\"name\\\": \\\"SonarQube2\\\",\"\r\n                                                    + \"                         \\\"slug\\\": \\\"sonarqube2\\\",\"\r\n                                                    + \"                         \\\"email\\\": \\\"sq2@email.com\\\",\"\r\n                                                    + \"                       },\"\r\n                                                    + \"                }\"\r\n                                                    + \"            ]\"\r\n                                                    + \"        }\"\r\n                                                    + \"    ]\"\r\n                                                    + \"}\";\r\n\r\n  public static String baseReportWithEmptyFileComments = \"{\\\"diffs\\\": [\"\r\n                                                         + \"        {\"\r\n                                                         + \"            \\\"source\\\": {\"\r\n                                                         + \"                \\\"components\\\": [\"\r\n                                                         + \"                    \\\"Test.java\\\"\"\r\n                                                         + \"                ],\"\r\n                                                         + \"                \\\"toString\\\": \\\"stash-plugin/Test.java\\\"\"\r\n                                                         + \"            },\"\r\n                                                         + \"            \\\"destination\\\": {\"\r\n                                                         + \"                \\\"components\\\": [\"\r\n                                                         + \"                    \\\"Test.java\\\"\"\r\n                                                         + \"               ],\"\r\n                                                         + \"               \\\"toString\\\": \\\"stash-plugin/Test.java\\\"\"\r\n                                                         + \"            },\"\r\n                                                         + \"            \\\"hunks\\\": [\"\r\n                                                         + \"                {\"\r\n                                                         + \"                    \\\"segments\\\": [\"\r\n                                                         + \"                        {\"\r\n                                                         + \"                            \\\"type\\\": \\\"CONTEXT\\\",\"\r\n                                                         + \"                            \\\"lines\\\": [\"\r\n                                                         + \"                                {\"\r\n                                                         + \"                                    \\\"source\\\": 10,\"\r\n                                                         + \"                                    \\\"destination\\\": 20,\"\r\n                                                         + \"                                    \\\"line\\\": \\\"System.out.println(test);\\\",\"\r\n                                                         + \"                                    \\\"commentIds\\\": [\"\r\n                                                         + \"                                     12345\"\r\n                                                         + \"                                    ]\"\r\n                                                         + \"                                }\"\r\n                                                         + \"                            ],\"\r\n                                                         + \"                        },\"\r\n                                                         + \"                        {\"\r\n                                                         + \"                            \\\"type\\\": \\\"REMOVED\\\",\"\r\n                                                         + \"                            \\\"lines\\\": [\"\r\n                                                         + \"                                {\"\r\n                                                         + \"                                    \\\"source\\\": 20,\"\r\n                                                         + \"                                    \\\"destination\\\": 30,\"\r\n                                                         + \"                                }\"\r\n                                                         + \"                            ],\"\r\n                                                         + \"                        },\"\r\n                                                         + \"                        {\"\r\n                                                         + \"                            \\\"type\\\": \\\"ADDED\\\",\"\r\n                                                         + \"                            \\\"lines\\\": [\"\r\n                                                         + \"                                {\"\r\n                                                         + \"                                    \\\"source\\\": 30,\"\r\n                                                         + \"                                    \\\"destination\\\": 40,\"\r\n                                                         + \"                                    \\\"line\\\": \\\"System.out.println(test);\\\",\"\r\n                                                         + \"                                }\"\r\n                                                         + \"                            ],\"\r\n                                                         + \"                        },\"\r\n                                                         + \"                        {\"\r\n                                                         + \"                            \\\"type\\\": \\\"CONTEXT\\\",\"\r\n                                                         + \"                            \\\"lines\\\": [\"\r\n                                                         + \"                                {\"\r\n                                                         + \"                                   \\\"source\\\": 40,\"\r\n                                                         + \"                                    \\\"destination\\\": 50,\"\r\n                                                         + \"                                    \\\"line\\\": \\\"System.out.println(test);\\\",\"\r\n                                                         + \"                                    \\\"commentIds\\\": [\"\r\n                                                         + \"                                        54321\"\r\n                                                         + \"                                    ]\"\r\n                                                         + \"                               }\"\r\n                                                         + \"                            ],\"\r\n                                                         + \"                        },\"\r\n                                                         + \"                        {\"\r\n                                                         + \"                            \\\"type\\\": \\\"REMOVED\\\",\"\r\n                                                         + \"                            \\\"lines\\\": [\"\r\n                                                         + \"                                {\"\r\n                                                         + \"                                    \\\"source\\\": 50,\"\r\n                                                         + \"                                    \\\"destination\\\": 60,\"\r\n                                                         + \"                                    \\\"line\\\": \\\"System.out.println(test);\\\",\"\r\n                                                         + \"                                }\"\r\n                                                         + \"                            ],\"\r\n                                                         + \"                        },\"\r\n                                                         + \"                        {\"\r\n                                                         + \"                            \\\"type\\\": \\\"ADDED\\\",\"\r\n                                                         + \"                            \\\"lines\\\": [\"\r\n                                                         + \"                                {\"\r\n                                                         + \"                                    \\\"source\\\": 60,\"\r\n                                                         + \"                                    \\\"destination\\\": 70,\"\r\n                                                         + \"                                    \\\"line\\\": \\\"System.out.println(test);\\\",\"\r\n                                                         + \"                                }\"\r\n                                                         + \"                            ],\"\r\n                                                         + \"                        },\"\r\n                                                         + \"                    ],\"\r\n                                                         + \"                }\"\r\n                                                         + \"            ],\"\r\n                                                         + \"            \\\"lineComments\\\": [\"\r\n                                                         + \"                {\"\r\n                                                         + \"                    \\\"id\\\": 12345,\"\r\n                                                         + \"                    \\\"text\\\": \\\"Test comment\\\",\"\r\n                                                         + \"                    \\\"version\\\": 1,\"\r\n                                                         + \"                    \\\"author\\\": \"\r\n                                                         + \"                       {\"\r\n                                                         + \"                         \\\"id\\\": 12345,\"\r\n                                                         + \"                         \\\"name\\\": \\\"SonarQube\\\",\"\r\n                                                         + \"                         \\\"slug\\\": \\\"sonarqube\\\",\"\r\n                                                         + \"                         \\\"email\\\": \\\"sq@email.com\\\",\"\r\n                                                         + \"                       },\"\r\n                                                         + \"                },\"\r\n                                                         + \"                {\"\r\n                                                         + \"                    \\\"id\\\": 54321,\"\r\n                                                         + \"                    \\\"text\\\": \\\"Test comment 2\\\",\"\r\n                                                         + \"                    \\\"version\\\": 1,\"\r\n                                                         + \"                    \\\"author\\\": \"\r\n                                                         + \"                       {\"\r\n                                                         + \"                         \\\"id\\\": 54321,\"\r\n                                                         + \"                         \\\"name\\\": \\\"SonarQube2\\\",\"\r\n                                                         + \"                         \\\"slug\\\": \\\"sonarqube2\\\",\"\r\n                                                         + \"                         \\\"email\\\": \\\"sq2@email.com\\\",\"\r\n                                                         + \"                       },\"\r\n                                                         + \"                }\"\r\n                                                         + \"            ]\"\r\n                                                         + \"            \\\"fileComments\\\": []\"\r\n                                                         + \"        }\"\r\n                                                         + \"    ]\"\r\n                                                         + \"}\";\r\n\r\n  public static String emptyReport = \"{\\\"diffs\\\": [\"\r\n                                     + \"        {\"\r\n                                     + \"            \\\"source\\\": {\"\r\n                                     + \"                \\\"components\\\": [\"\r\n                                     + \"                    \\\"Test.java\\\"\"\r\n                                     + \"                ],\"\r\n                                     + \"                \\\"toString\\\": \\\"stash-plugin/Test.java\\\"\"\r\n                                     + \"            },\"\r\n                                     + \"                \\\"destination\\\": {\"\r\n                                     + \"                \\\"components\\\": [\"\r\n                                     + \"                    \\\"Test.java\\\"\"\r\n                                     + \"               ],\"\r\n                                     + \"                \\\"toString\\\": \\\"stash-plugin/Test.java\\\"\"\r\n                                     + \"            },\"\r\n                                     + \"            \\\"hunks\\\": [],\"\r\n                                     + \"            \\\"lineComments\\\": []\"\r\n                                     + \"        }\"\r\n                                     + \"    ]\"\r\n                                     + \"}\";\r\n\r\n  public static String multipleFileReport = \"{\\\"diffs\\\": [\"\r\n                                            + \"        {\"\r\n                                            + \"            \\\"source\\\": {\"\r\n                                            + \"                \\\"components\\\": [\"\r\n                                            + \"                    \\\"Test.java\\\"\"\r\n                                            + \"                ],\"\r\n                                            + \"                \\\"toString\\\": \\\"stash-plugin/Test.java\\\"\"\r\n                                            + \"            },\"\r\n                                            + \"            \\\"destination\\\": {\"\r\n                                            + \"                \\\"components\\\": [\"\r\n                                            + \"                    \\\"Test.java\\\"\"\r\n                                            + \"               ],\"\r\n                                            + \"               \\\"toString\\\": \\\"stash-plugin/Test.java\\\"\"\r\n                                            + \"            },\"\r\n                                            + \"            \\\"hunks\\\": [\"\r\n                                            + \"                {\"\r\n                                            + \"                    \\\"segments\\\": [\"\r\n                                            + \"                        {\"\r\n                                            + \"                            \\\"type\\\": \\\"CONTEXT\\\",\"\r\n                                            + \"                            \\\"lines\\\": [\"\r\n                                            + \"                                {\"\r\n                                            + \"                                    \\\"source\\\": 10,\"\r\n                                            + \"                                    \\\"destination\\\": 20,\"\r\n                                            + \"                                    \\\"line\\\": \\\"System.out.println(test);\\\",\"\r\n                                            + \"                                    \\\"commentIds\\\": [\"\r\n                                            + \"                                     12345\"\r\n                                            + \"                                    ]\"\r\n                                            + \"                                }\"\r\n                                            + \"                            ],\"\r\n                                            + \"                        }\"\r\n                                            + \"                    ],\"\r\n                                            + \"                }\"\r\n                                            + \"            ],\"\r\n                                            + \"            \\\"lineComments\\\": [\"\r\n                                            + \"                {\"\r\n                                            + \"                    \\\"id\\\": 12345,\"\r\n                                            + \"                    \\\"text\\\": \\\"Test comment\\\",\"\r\n                                            + \"                    \\\"version\\\": 1,\"\r\n                                            + \"                    \\\"author\\\": \"\r\n                                            + \"                       {\"\r\n                                            + \"                         \\\"id\\\": 12345,\"\r\n                                            + \"                         \\\"name\\\": \\\"SonarQube\\\",\"\r\n                                            + \"                         \\\"slug\\\": \\\"sonarqube\\\",\"\r\n                                            + \"                         \\\"email\\\": \\\"sq@email.com\\\",\"\r\n                                            + \"                       },\"\r\n                                            + \"                }\"\r\n                                            + \"            ]\"\r\n                                            + \"        },\"\r\n                                            + \"        {\"\r\n                                            + \"            \\\"source\\\": {\"\r\n                                            + \"                \\\"components\\\": [\"\r\n                                            + \"                    \\\"Test1.java\\\"\"\r\n                                            + \"                ],\"\r\n                                            + \"                \\\"toString\\\": \\\"stash-plugin/Test1.java\\\"\"\r\n                                            + \"            },\"\r\n                                            + \"            \\\"destination\\\": {\"\r\n                                            + \"                \\\"components\\\": [\"\r\n                                            + \"                    \\\"Test1.java\\\"\"\r\n                                            + \"               ],\"\r\n                                            + \"               \\\"toString\\\": \\\"stash-plugin/Test1.java\\\"\"\r\n                                            + \"            },\"\r\n                                            + \"            \\\"hunks\\\": [\"\r\n                                            + \"                {\"\r\n                                            + \"                    \\\"segments\\\": [\"\r\n                                            + \"                        {\"\r\n                                            + \"                            \\\"type\\\": \\\"ADDED\\\",\"\r\n                                            + \"                            \\\"lines\\\": [\"\r\n                                            + \"                                {\"\r\n                                            + \"                                    \\\"source\\\": 20,\"\r\n                                            + \"                                    \\\"destination\\\": 30,\"\r\n                                            + \"                                    \\\"line\\\": \\\"System.out.println(test);\\\",\"\r\n                                            + \"                                    \\\"commentIds\\\": []\"\r\n                                            + \"                                }\"\r\n                                            + \"                            ],\"\r\n                                            + \"                        }\"\r\n                                            + \"                    ],\"\r\n                                            + \"                }\"\r\n                                            + \"            ],\"\r\n                                            + \"            \\\"lineComments\\\": []\"\r\n                                            + \"        }\"\r\n                                            + \"    ]\"\r\n                                            + \"}\";\r\n\r\n  public static String baseReportWithNoComments = \"{\\\"diffs\\\": [\"\r\n                                                  + \"        {\"\r\n                                                  + \"            \\\"source\\\": {\"\r\n                                                  + \"                \\\"components\\\": [\"\r\n                                                  + \"                    \\\"Test.java\\\"\"\r\n                                                  + \"                ],\"\r\n                                                  + \"                \\\"toString\\\": \\\"stash-plugin/Test.java\\\"\"\r\n                                                  + \"            },\"\r\n                                                  + \"            \\\"destination\\\": {\"\r\n                                                  + \"                \\\"components\\\": [\"\r\n                                                  + \"                    \\\"Test.java\\\"\"\r\n                                                  + \"               ],\"\r\n                                                  + \"               \\\"toString\\\": \\\"stash-plugin/Test.java\\\"\"\r\n                                                  + \"            },\"\r\n                                                  + \"            \\\"hunks\\\": [\"\r\n                                                  + \"                {\"\r\n                                                  + \"                    \\\"segments\\\": [\"\r\n                                                  + \"                        {\"\r\n                                                  + \"                            \\\"type\\\": \\\"CONTEXT\\\",\"\r\n                                                  + \"                            \\\"lines\\\": [\"\r\n                                                  + \"                                {\"\r\n                                                  + \"                                    \\\"source\\\": 10,\"\r\n                                                  + \"                                    \\\"destination\\\": 20,\"\r\n                                                  + \"                                    \\\"line\\\": \\\"System.out.println(test);\\\"\"\r\n                                                  + \"                                }\"\r\n                                                  + \"                            ],\"\r\n                                                  + \"                        },\"\r\n                                                  + \"                        {\"\r\n                                                  + \"                            \\\"type\\\": \\\"REMOVED\\\",\"\r\n                                                  + \"                            \\\"lines\\\": [\"\r\n                                                  + \"                                {\"\r\n                                                  + \"                                    \\\"source\\\": 20,\"\r\n                                                  + \"                                    \\\"destination\\\": 30,\"\r\n                                                  + \"                                }\"\r\n                                                  + \"                            ],\"\r\n                                                  + \"                        },\"\r\n                                                  + \"                        {\"\r\n                                                  + \"                            \\\"type\\\": \\\"ADDED\\\",\"\r\n                                                  + \"                            \\\"lines\\\": [\"\r\n                                                  + \"                                {\"\r\n                                                  + \"                                    \\\"source\\\": 30,\"\r\n                                                  + \"                                    \\\"destination\\\": 40,\"\r\n                                                  + \"                                    \\\"line\\\": \\\"System.out.println(test);\\\",\"\r\n                                                  + \"                                }\"\r\n                                                  + \"                            ],\"\r\n                                                  + \"                        },\"\r\n                                                  + \"                        {\"\r\n                                                  + \"                            \\\"type\\\": \\\"CONTEXT\\\",\"\r\n                                                  + \"                            \\\"lines\\\": [\"\r\n                                                  + \"                                {\"\r\n                                                  + \"                                   \\\"source\\\": 40,\"\r\n                                                  + \"                                    \\\"destination\\\": 50,\"\r\n                                                  + \"                                    \\\"line\\\": \\\"System.out.println(test);\\\"\"\r\n                                                  + \"                               }\"\r\n                                                  + \"                            ],\"\r\n                                                  + \"                        },\"\r\n                                                  + \"                        {\"\r\n                                                  + \"                            \\\"type\\\": \\\"REMOVED\\\",\"\r\n                                                  + \"                            \\\"lines\\\": [\"\r\n                                                  + \"                                {\"\r\n                                                  + \"                                    \\\"source\\\": 50,\"\r\n                                                  + \"                                    \\\"destination\\\": 60,\"\r\n                                                  + \"                                    \\\"line\\\": \\\"System.out.println(test);\\\",\"\r\n                                                  + \"                                }\"\r\n                                                  + \"                            ],\"\r\n                                                  + \"                        },\"\r\n                                                  + \"                        {\"\r\n                                                  + \"                            \\\"type\\\": \\\"ADDED\\\",\"\r\n                                                  + \"                            \\\"lines\\\": [\"\r\n                                                  + \"                                {\"\r\n                                                  + \"                                    \\\"source\\\": 60,\"\r\n                                                  + \"                                    \\\"destination\\\": 70,\"\r\n                                                  + \"                                    \\\"line\\\": \\\"System.out.println(test);\\\",\"\r\n                                                  + \"                                }\"\r\n                                                  + \"                            ],\"\r\n                                                  + \"                        },\"\r\n                                                  + \"                    ],\"\r\n                                                  + \"                }\"\r\n                                                  + \"            ],\"\r\n                                                  + \"            \\\"lineComments\\\": []\"\r\n                                                  + \"        }\"\r\n                                                  + \"    ]\"\r\n                                                  + \"}\";\r\n\r\n  public static String deletedFileReport = \"{\\\"diffs\\\": [\"\r\n                                           + \"        {\"\r\n                                           + \"            \\\"source\\\": {\"\r\n                                           + \"                \\\"components\\\": [\"\r\n                                           + \"                    \\\"Test.java\\\"\"\r\n                                           + \"                ],\"\r\n                                           + \"                \\\"toString\\\": \\\"stash-plugin/Test.java\\\"\"\r\n                                           + \"            },\"\r\n                                           + \"            \\\"destination\\\": null,\"\r\n                                           + \"            \\\"hunks\\\": [\"\r\n                                           + \"                {\"\r\n                                           + \"                    \\\"segments\\\": [\"\r\n                                           + \"                        {\"\r\n                                           + \"                            \\\"type\\\": \\\"REMOVED\\\",\"\r\n                                           + \"                            \\\"lines\\\": [\"\r\n                                           + \"                                {\"\r\n                                           + \"                                    \\\"source\\\": 1,\"\r\n                                           + \"                                    \\\"destination\\\": 0,\"\r\n                                           + \"                                    \\\"line\\\": \\\"System.out.println(test);\\\"\"\r\n                                           + \"                                }\"\r\n                                           + \"                            ],\"\r\n                                           + \"                        },\"\r\n                                           + \"                        {\"\r\n                                           + \"                            \\\"type\\\": \\\"REMOVED\\\",\"\r\n                                           + \"                            \\\"lines\\\": [\"\r\n                                           + \"                                {\"\r\n                                           + \"                                    \\\"source\\\": 2,\"\r\n                                           + \"                                    \\\"destination\\\": 0,\"\r\n                                           + \"                                    \\\"line\\\": \\\"System.out.println(test);\\\"\"\r\n                                           + \"                                }\"\r\n                                           + \"                            ],\"\r\n                                           + \"                        },\"\r\n                                           + \"                        {\"\r\n                                           + \"                            \\\"type\\\": \\\"REMOVED\\\",\"\r\n                                           + \"                            \\\"lines\\\": [\"\r\n                                           + \"                                {\"\r\n                                           + \"                                    \\\"source\\\": 3,\"\r\n                                           + \"                                    \\\"destination\\\": 0,\"\r\n                                           + \"                                    \\\"line\\\": \\\"System.out.println(test);\\\"\"\r\n                                           + \"                                }\"\r\n                                           + \"                            ],\"\r\n                                           + \"                        },\"\r\n                                           + \"                    ],\"\r\n                                           + \"                }\"\r\n                                           + \"            ],\"\r\n                                           + \"        }\"\r\n                                           + \"        {\"\r\n                                           + \"            \\\"source\\\": {\"\r\n                                           + \"                \\\"components\\\": [\"\r\n                                           + \"                    \\\"Test2.java\\\"\"\r\n                                           + \"                ],\"\r\n                                           + \"                \\\"toString\\\": \\\"stash-plugin/Test2.java\\\"\"\r\n                                           + \"            },\"\r\n                                           + \"            \\\"destination\\\": {\"\r\n                                           + \"                \\\"components\\\": [\"\r\n                                           + \"                    \\\"Test2.java\\\"\"\r\n                                           + \"               ],\"\r\n                                           + \"               \\\"toString\\\": \\\"stash-plugin/Test2.java\\\"\"\r\n                                           + \"            },\"\r\n                                           + \"            \\\"hunks\\\": [\"\r\n                                           + \"                {\"\r\n                                           + \"                    \\\"segments\\\": [\"\r\n                                           + \"                        {\"\r\n                                           + \"                            \\\"type\\\": \\\"CONTEXT\\\",\"\r\n                                           + \"                            \\\"lines\\\": [\"\r\n                                           + \"                                {\"\r\n                                           + \"                                    \\\"source\\\": 10,\"\r\n                                           + \"                                    \\\"destination\\\": 20,\"\r\n                                           + \"                                    \\\"line\\\": \\\"System.out.println(test);\\\",\"\r\n                                           + \"                                }\"\r\n                                           + \"                            ],\"\r\n                                           + \"                        },\"\r\n                                           + \"                        {\"\r\n                                           + \"                            \\\"type\\\": \\\"REMOVED\\\",\"\r\n                                           + \"                            \\\"lines\\\": [\"\r\n                                           + \"                                {\"\r\n                                           + \"                                    \\\"source\\\": 20,\"\r\n                                           + \"                                    \\\"destination\\\": 30,\"\r\n                                           + \"                                }\"\r\n                                           + \"                            ],\"\r\n                                           + \"                        },\"\r\n                                           + \"                        {\"\r\n                                           + \"                            \\\"type\\\": \\\"ADDED\\\",\"\r\n                                           + \"                            \\\"lines\\\": [\"\r\n                                           + \"                                {\"\r\n                                           + \"                                    \\\"source\\\": 30,\"\r\n                                           + \"                                    \\\"destination\\\": 40,\"\r\n                                           + \"                                    \\\"line\\\": \\\"System.out.println(test);\\\",\"\r\n                                           + \"                                }\"\r\n                                           + \"                            ],\"\r\n                                           + \"                        },\"\r\n                                           + \"                    ],\"\r\n                                           + \"                }\"\r\n                                           + \"            ],\"\r\n                                           + \"        }\"\r\n                                           + \"    ]\"\r\n                                           + \"}\";\r\n}\r\n"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/issue/collector/SonarQubeCollectorTest.java",
    "content": "package org.sonar.plugins.stash.issue.collector;\r\n\r\nimport java.util.HashSet;\r\nimport java.util.Set;\r\n\r\nimport static org.junit.jupiter.api.Assertions.assertEquals;\r\nimport static org.junit.jupiter.api.Assertions.assertFalse;\r\nimport static org.junit.jupiter.api.Assertions.assertNull;\r\nimport static org.junit.jupiter.api.Assertions.assertTrue;\r\nimport static org.mockito.Mockito.mock;\r\nimport static org.mockito.Mockito.when;\r\nimport static org.sonar.plugins.stash.StashPluginUtils.countIssuesBySeverity;\r\nimport static org.sonar.plugins.stash.TestUtils.inputFile;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\nimport org.junit.jupiter.api.BeforeEach;\r\nimport org.junit.jupiter.api.Test;\r\nimport org.junit.jupiter.api.extension.ExtendWith;\r\nimport org.mockito.Mock;\r\nimport org.mockito.junit.jupiter.MockitoExtension;\r\nimport org.mockito.junit.jupiter.MockitoSettings;\r\nimport org.mockito.quality.Strictness;\r\nimport org.sonar.api.batch.fs.InputComponent;\r\nimport org.sonar.api.batch.fs.InputFile;\r\nimport org.sonar.api.batch.fs.internal.DefaultInputFile;\r\nimport org.sonar.api.batch.postjob.issue.PostJobIssue;\r\nimport org.sonar.api.batch.rule.Severity;\r\nimport org.sonar.api.rule.RuleKey;\r\nimport org.sonar.plugins.stash.DefaultIssue;\r\nimport org.sonar.plugins.stash.IssuePathResolver;\r\nimport org.sonar.plugins.stash.fixtures.DummyIssuePathResolver;\r\n\r\n@ExtendWith(MockitoExtension.class)\r\n@MockitoSettings(strictness = Strictness.LENIENT)\r\npublic class SonarQubeCollectorTest {\r\n\r\n  @Mock\r\n  DefaultIssue issue1;\r\n\r\n  @Mock\r\n  DefaultIssue issue2;\r\n\r\n  @Mock\r\n  InputFile inputFile1;\r\n\r\n  @Mock\r\n  InputFile inputFile2;\r\n\r\n  Set<RuleKey> excludedRules;\r\n\r\n  IssuePathResolver ipr = new DummyIssuePathResolver();\r\n\r\n  @BeforeEach\r\n  public void setUp() throws Exception {\r\n\r\n    ///////// SonarQube issues /////////\r\n\r\n    when(issue1.line()).thenReturn(1);\r\n    when(issue1.message()).thenReturn(\"message1\");\r\n    when(issue1.key()).thenReturn(\"key1\");\r\n    when(issue1.severity()).thenReturn(Severity.BLOCKER);\r\n    when(issue1.componentKey()).thenReturn(\"module1:component1\");\r\n    when(issue1.isNew()).thenReturn(true);\r\n    when(issue1.inputComponent()).thenReturn(inputFile(\"module1\", \"file1\"));\r\n\r\n    RuleKey rule1 = mock(RuleKey.class);\r\n    when(rule1.toString()).thenReturn(\"rule1\");\r\n    when(issue1.ruleKey()).thenReturn(rule1);\r\n\r\n    when(issue2.line()).thenReturn(2);\r\n    when(issue2.message()).thenReturn(\"message2\");\r\n    when(issue2.key()).thenReturn(\"key2\");\r\n    when(issue2.severity()).thenReturn(Severity.CRITICAL);\r\n    when(issue2.componentKey()).thenReturn(\"module2:component2\");\r\n    when(issue2.isNew()).thenReturn(true);\r\n    when(issue2.inputComponent()).thenReturn(inputFile(\"module2\", \"file2\"));\r\n\r\n    RuleKey rule2 = mock(RuleKey.class);\r\n    when(rule2.toString()).thenReturn(\"rule2\");\r\n    when(issue2.ruleKey()).thenReturn(rule2);\r\n\r\n    inputFile1 = inputFile(\"module1\", \"project/path1\");\r\n    inputFile2 = inputFile(\"module2\", \"project/path2\");\r\n    when(issue1.inputComponent()).thenReturn(inputFile1);\r\n    when(issue2.inputComponent()).thenReturn(inputFile2);\r\n\r\n    excludedRules = new HashSet<>();\r\n  }\r\n\r\n  @Test\r\n  public void testExtractEmptyIssueReport() {\r\n    ArrayList<PostJobIssue> issues = new ArrayList<>();\r\n\r\n    List<PostJobIssue> report = SonarQubeCollector.extractIssueReport(issues, ipr, false, excludedRules);\r\n    assertEquals(0, report.size());\r\n  }\r\n\r\n  @Test\r\n  public void testExtractIssueReport() {\r\n    ArrayList<PostJobIssue> issues = new ArrayList<>();\r\n    issues.add(issue1);\r\n    issues.add(issue2);\r\n\r\n    List<PostJobIssue> report = SonarQubeCollector.extractIssueReport(issues, ipr, false, excludedRules);\r\n    assertEquals(2, report.size());\r\n    assertEquals(1, countIssuesBySeverity(report, Severity.BLOCKER));\r\n    assertEquals(1, countIssuesBySeverity(report, Severity.CRITICAL));\r\n\r\n    PostJobIssue sqIssue1 = report.get(0);\r\n    assertEquals(\"message1\", sqIssue1.message());\r\n    assertEquals(\"project/path1\", ipr.getIssuePath(sqIssue1));\r\n    assertEquals((Integer) 1, sqIssue1.line());\r\n\r\n    PostJobIssue sqIssue2 = report.get(1);\r\n    assertEquals(\"message2\", sqIssue2.message());\r\n    assertEquals(\"project/path2\", ipr.getIssuePath(sqIssue2));\r\n    assertEquals((Integer) 2, sqIssue2.line());\r\n\r\n  }\r\n\r\n  @Test\r\n  public void testExtractIssueReportWithNoLine() {\r\n    when(issue1.line()).thenReturn(null);\r\n\r\n    ArrayList<PostJobIssue> issues = new ArrayList<>();\r\n    issues.add(issue1);\r\n\r\n    List<PostJobIssue> report = SonarQubeCollector.extractIssueReport(issues, ipr, false, excludedRules);\r\n    assertEquals(1, report.size());\r\n    assertEquals(1, countIssuesBySeverity(report, Severity.BLOCKER));\r\n    assertEquals(0, countIssuesBySeverity(report, Severity.CRITICAL));\r\n\r\n    PostJobIssue sqIssue1 = report.get(0);\r\n    assertEquals(\"message1\", sqIssue1.message());\r\n    assertEquals(\"project/path1\", ipr.getIssuePath(sqIssue1));\r\n    assertNull(sqIssue1.line());\r\n  }\r\n\r\n  @Test\r\n  public void testExtractIssueReportWithOldOption() {\r\n    when(issue1.isNew()).thenReturn(false);\r\n    when(issue2.isNew()).thenReturn(true);\r\n\r\n    ArrayList<PostJobIssue> issues = new ArrayList<>();\r\n    issues.add(issue1);\r\n    issues.add(issue2);\r\n\r\n    List<PostJobIssue> report = SonarQubeCollector.extractIssueReport(issues, ipr, false, excludedRules);\r\n    assertEquals(1, report.size());\r\n    assertEquals(0, countIssuesBySeverity(report, Severity.BLOCKER));\r\n    assertEquals(1, countIssuesBySeverity(report, Severity.CRITICAL));\r\n  }\r\n\r\n  @Test\r\n  public void testExtractIssueReportWithOneIssueWithoutInputFile() {\r\n    when(issue1.inputComponent()).thenReturn(null);\r\n\r\n    ArrayList<PostJobIssue> issues = new ArrayList<>();\r\n    issues.add(issue1);\r\n    issues.add(issue2);\r\n\r\n    List<PostJobIssue> report = SonarQubeCollector.extractIssueReport(issues, ipr, false, excludedRules);\r\n    assertEquals(1, report.size());\r\n    assertEquals(0, countIssuesBySeverity(report, Severity.BLOCKER));\r\n    assertEquals(1, countIssuesBySeverity(report, Severity.CRITICAL));\r\n\r\n    PostJobIssue sqIssue2 = report.get(0);\r\n    assertEquals(\"message2\", sqIssue2.message());\r\n    assertEquals(\"project/path2\", ipr.getIssuePath(sqIssue2));\r\n    assertEquals((Integer) 2, sqIssue2.line());\r\n  }\r\n\r\n  @Test\r\n  public void testExtractIssueReportWithIncludeExistingIssuesOption() {\r\n    when(issue1.isNew()).thenReturn(false);\r\n    when(issue2.isNew()).thenReturn(true);\r\n\r\n    ArrayList<PostJobIssue> issues = new ArrayList<>();\r\n    issues.add(issue1);\r\n    issues.add(issue2);\r\n\r\n    List<PostJobIssue> report = SonarQubeCollector.extractIssueReport(issues, ipr, true, excludedRules);\r\n    assertEquals(2, report.size());\r\n  }\r\n\r\n  @Test\r\n  public void testExtractIssueReportWithExcludedRules() {\r\n    when(issue1.ruleKey()).thenReturn(RuleKey.of(\"foo\", \"bar\"));\r\n    when(issue2.ruleKey()).thenReturn(RuleKey.of(\"foo\", \"baz\"));\r\n\r\n    ArrayList<PostJobIssue> issues = new ArrayList<>();\r\n    issues.add(issue1);\r\n    issues.add(issue2);\r\n\r\n    excludedRules.add(RuleKey.of(\"foo\", \"bar\"));\r\n\r\n    List<PostJobIssue> report = SonarQubeCollector.extractIssueReport(issues, ipr, true, excludedRules);\r\n    assertEquals(1, report.size());\r\n    assertEquals(\"key2\", report.get(0).key());\r\n  }\r\n\r\n  @Test\r\n  public void testShouldIncludeIssue() {\r\n    Set<RuleKey> er = new HashSet<>();\r\n    InputComponent ic = inputFile(\"module\", \"some/path\");\r\n\r\n    assertFalse(\r\n        SonarQubeCollector.shouldIncludeIssue(\r\n            new DefaultIssue().setNew(false).setInputComponent(ic), ipr, false, er\r\n        )\r\n    );\r\n    assertTrue(\r\n        SonarQubeCollector.shouldIncludeIssue(\r\n            new DefaultIssue().setNew(false).setInputComponent(ic), ipr, true, er\r\n        )\r\n    );\r\n    assertTrue(\r\n        SonarQubeCollector.shouldIncludeIssue(\r\n            new DefaultIssue().setNew(true).setInputComponent(ic), ipr, false, er\r\n        )\r\n    );\r\n    assertTrue(\r\n        SonarQubeCollector.shouldIncludeIssue(\r\n            new DefaultIssue().setNew(true).setInputComponent(ic), ipr, true, er\r\n        )\r\n    );\r\n  }\r\n}\r\n"
  },
  {
    "path": "src/test/java/org/sonar/plugins/stash/issue/collector/StashCollectorTest.java",
    "content": "package org.sonar.plugins.stash.issue.collector;\r\n\r\nimport static org.junit.jupiter.api.Assertions.assertEquals;\r\nimport static org.junit.jupiter.api.Assertions.assertFalse;\r\nimport static org.junit.jupiter.api.Assertions.assertThrows;\r\nimport static org.junit.jupiter.api.Assertions.assertTrue;\r\n\r\nimport com.github.cliftonlabs.json_simple.JsonObject;\r\nimport com.github.cliftonlabs.json_simple.Jsoner;\r\nimport org.junit.jupiter.api.Test;\r\nimport org.sonar.plugins.stash.PullRequestRef;\r\nimport org.sonar.plugins.stash.StashPlugin.IssueType;\r\nimport org.sonar.plugins.stash.exceptions.StashReportExtractionException;\r\nimport org.sonar.plugins.stash.issue.StashComment;\r\nimport org.sonar.plugins.stash.issue.StashCommentReport;\r\nimport org.sonar.plugins.stash.issue.StashDiff;\r\nimport org.sonar.plugins.stash.issue.StashDiffReport;\r\nimport org.sonar.plugins.stash.issue.StashPullRequest;\r\nimport org.sonar.plugins.stash.issue.StashTask;\r\nimport org.sonar.plugins.stash.issue.StashUser;\r\n\r\npublic class StashCollectorTest {\r\n\r\n  private static final long STASH_USER_ID = 1;\r\n  PullRequestRef pr = PullRequestRef.builder()\r\n                                    .setProject(\"project\")\r\n                                    .setRepository(\"repository\")\r\n                                    .setPullRequestId(123)\r\n                                    .build();\r\n\r\n  @Test\r\n  public void testExtractCommentReport() throws Exception {\r\n    String commentString =\r\n        \"{\\\"values\\\": [{\\\"id\\\":1234, \\\"text\\\":\\\"message\\\", \\\"anchor\\\": {\\\"path\\\":\\\"path\\\", \\\"line\\\":5},\"\r\n        + \"\\\"author\\\": {\\\"id\\\":1, \\\"name\\\":\\\"SonarQube\\\", \\\"slug\\\":\\\"sonarqube\\\", \\\"email\\\":\\\"sq@email.com\\\"}, \\\"version\\\":0}]}\";\r\n    StashCommentReport commentReport = StashCollector.extractComments(parse(commentString));\r\n\r\n    assertEquals(1, commentReport.size());\r\n\r\n    StashComment comment = commentReport.getComments().get(0);\r\n    assertEquals(1234, comment.getId());\r\n    assertEquals(\"message\", comment.getMessage());\r\n    assertEquals(\"path\", comment.getPath());\r\n    assertEquals(0, comment.getVersion());\r\n    assertEquals(STASH_USER_ID, comment.getAuthor().getId());\r\n    assertEquals(5, comment.getLine());\r\n  }\r\n\r\n  @Test\r\n  public void testExtractCommentReportWithSeveralComment() throws Exception {\r\n    String commentString = \"{\\\"values\\\": [\"\r\n                           + \"{\\\"id\\\":1234, \\\"text\\\":\\\"message1\\\", \\\"anchor\\\": {\\\"path\\\":\\\"path1\\\", \\\"line\\\":1},\"\r\n                           + \"\\\"author\\\": {\\\"id\\\":1, \\\"name\\\":\\\"SonarQube\\\", \\\"slug\\\":\\\"sonarqube\\\", \\\"email\\\":\\\"sq@email.com\\\"}, \\\"version\\\":1}, \"\r\n                           + \"{\\\"id\\\":5678, \\\"text\\\":\\\"message2\\\", \\\"anchor\\\": {\\\"path\\\":\\\"path2\\\", \\\"line\\\":2},\"\r\n                           + \"\\\"author\\\": {\\\"id\\\":1, \\\"name\\\":\\\"SonarQube\\\", \\\"slug\\\":\\\"sonarqube\\\", \\\"email\\\":\\\"sq@email.com\\\"}, \\\"version\\\":2}]}\";\r\n\r\n    StashCommentReport commentReport = StashCollector.extractComments(parse(commentString));\r\n\r\n    assertEquals(2, commentReport.size());\r\n\r\n    StashComment comment1 = commentReport.getComments().get(0);\r\n    assertEquals(1234, comment1.getId());\r\n    assertEquals(\"message1\", comment1.getMessage());\r\n    assertEquals(\"path1\", comment1.getPath());\r\n    assertEquals(1, comment1.getVersion());\r\n    assertEquals(STASH_USER_ID, comment1.getAuthor().getId());\r\n    assertEquals(1, comment1.getLine());\r\n\r\n    StashComment comment2 = commentReport.getComments().get(1);\r\n    assertEquals(5678, comment2.getId());\r\n    assertEquals(\"message2\", comment2.getMessage());\r\n    assertEquals(\"path2\", comment2.getPath());\r\n    assertEquals(2, comment2.getVersion());\r\n    assertEquals(STASH_USER_ID, comment2.getAuthor().getId());\r\n    assertEquals(2, comment2.getLine());\r\n  }\r\n\r\n  @Test\r\n  public void testExtractEmptyCommentReport() throws Exception {\r\n    String commentString = \"{\\\"values\\\": []}\";\r\n    StashCommentReport commentReport = StashCollector.extractComments(parse(commentString));\r\n\r\n    assertEquals(0, commentReport.size());\r\n  }\r\n\r\n  @Test\r\n  public void testExtractComment() throws Exception {\r\n    String commentString = \"{\\\"id\\\":1234, \\\"text\\\":\\\"message\\\", \\\"anchor\\\": {\\\"path\\\":\\\"path\\\", \\\"line\\\":5},\"\r\n                           + \"\\\"author\\\": {\\\"id\\\":1, \\\"name\\\":\\\"SonarQube\\\", \\\"slug\\\":\\\"sonarqube\\\", \\\"email\\\":\\\"sq@email.com\\\"}, \\\"version\\\":0}\";\r\n\r\n    StashComment comment = StashCollector.extractComment(parse(commentString));\r\n\r\n    assertEquals(1234, comment.getId());\r\n    assertEquals(\"message\", comment.getMessage());\r\n    assertEquals(\"path\", comment.getPath());\r\n    assertEquals(0, comment.getVersion());\r\n    assertEquals(STASH_USER_ID, comment.getAuthor().getId());\r\n    assertEquals(5, comment.getLine());\r\n  }\r\n\r\n  @Test\r\n  public void testExtractEmptyCommentWithNoAnchor() throws Exception {\r\n    String commentString = \"{\\\"id\\\":1234, \\\"text\\\":\\\"message\\\", \"\r\n                           + \"\\\"author\\\": {\\\"id\\\":1, \\\"name\\\":\\\"SonarQube\\\", \\\"slug\\\":\\\"sonarqube\\\", \\\"email\\\":\\\"sq@email.com\\\"}, \\\"version\\\":0}\";\r\n\r\n    assertThrows(StashReportExtractionException.class, () ->\r\n        StashCollector.extractComment(parse(commentString))\r\n    );\r\n  }\r\n\r\n  @Test\r\n  public void testExtractCommentWithPathAndLineAsParameters() throws Exception {\r\n    String commentString = \"{\\\"id\\\":1234, \\\"text\\\":\\\"message\\\", \\\"anchor\\\": {\\\"path\\\":\\\"path\\\", \\\"line\\\":5},\"\r\n                           + \"\\\"author\\\": {\\\"id\\\":1, \\\"name\\\":\\\"SonarQube\\\", \\\"slug\\\":\\\"sonarqube\\\", \\\"email\\\":\\\"sq@email.com\\\"}, \\\"version\\\":0}\";\r\n\r\n    StashComment comment = StashCollector.extractComment(parse(commentString), \"pathAsParameter\", (long)1111);\r\n\r\n    assertEquals(1234, comment.getId());\r\n    assertEquals(\"message\", comment.getMessage());\r\n    assertEquals(\"pathAsParameter\", comment.getPath());\r\n    assertEquals(0, comment.getVersion());\r\n    assertEquals(STASH_USER_ID, comment.getAuthor().getId());\r\n    assertEquals(1111, comment.getLine());\r\n  }\r\n\r\n  @Test\r\n  public void testIsLastPage() throws Exception {\r\n    String jsonBody = \"{\\\"isLastPage\\\": true}\";\r\n    assertTrue(StashCollector.isLastPage(parse(jsonBody)));\r\n\r\n    jsonBody = \"{\\\"isLastPage\\\": false}\";\r\n    assertFalse(StashCollector.isLastPage(parse(jsonBody)));\r\n\r\n    jsonBody = \"{\\\"values\\\": []}\";\r\n    assertTrue(StashCollector.isLastPage(parse(jsonBody)));\r\n  }\r\n\r\n  @Test\r\n  public void testNextPageStart() throws Exception {\r\n    String jsonBody = \"{\\\"nextPageStart\\\": 3}\";\r\n    assertEquals(3, StashCollector.getNextPageStart(parse(jsonBody)));\r\n\r\n    jsonBody = \"{\\\"values\\\": []}\";\r\n    assertEquals(0, StashCollector.getNextPageStart(parse(jsonBody)));\r\n  }\r\n\r\n  @Test\r\n  public void testExtractDiffsWithBaseReport() throws Exception {\r\n    StashDiffReport report = StashCollector.extractDiffs(parse(DiffReportSample.baseReport));\r\n    assertEquals(4, report.getDiffs().size());\r\n\r\n    StashDiff diff1 = report.getDiffs().get(0);\r\n    assertEquals((long)10, diff1.getSource());\r\n    assertEquals((long)20, diff1.getDestination());\r\n    assertEquals(\"stash-plugin/Test.java\", diff1.getPath());\r\n    assertEquals(IssueType.CONTEXT, diff1.getType());\r\n    assertEquals(1, diff1.getComments().size());\r\n    assertTrue(diff1.containsComment(12345));\r\n    assertFalse(diff1.containsComment(54321));\r\n\r\n    StashComment comment1 = diff1.getComments().get(0);\r\n    assertEquals(12345, comment1.getId());\r\n    assertEquals(\"Test comment\", comment1.getMessage());\r\n    assertEquals(1, comment1.getVersion());\r\n\r\n    StashTask task1 = comment1.getTasks().get(0);\r\n    assertEquals(12345, (long)task1.getId());\r\n    assertEquals(\"Complete the task associated to this TODO comment.\", task1.getText());\r\n    assertEquals(\"OPENED\", task1.getState());\r\n\r\n    StashTask task2 = comment1.getTasks().get(1);\r\n    assertEquals(54321, (long)task2.getId());\r\n    assertEquals(\"Complete the task associated to this TODO comment.\", task2.getText());\r\n    assertEquals(\"OPENED\", task2.getState());\r\n\r\n    StashUser author1 = comment1.getAuthor();\r\n    assertEquals(12345, author1.getId());\r\n    assertEquals(\"SonarQube\", author1.getName());\r\n    assertEquals(\"sonarqube\", author1.getSlug());\r\n    assertEquals(\"sq@email.com\", author1.getEmail());\r\n\r\n    StashDiff diff2 = report.getDiffs().get(1);\r\n    assertEquals((long)30, diff2.getSource());\r\n    assertEquals((long)40, diff2.getDestination());\r\n    assertEquals(\"stash-plugin/Test.java\", diff2.getPath());\r\n    assertEquals(IssueType.ADDED, diff2.getType());\r\n    assertEquals(0, diff2.getComments().size());\r\n    assertFalse(diff2.containsComment(12345));\r\n    assertFalse(diff2.containsComment(54321));\r\n\r\n    StashDiff diff3 = report.getDiffs().get(2);\r\n    assertEquals((long)40, diff3.getSource());\r\n    assertEquals((long)50, diff3.getDestination());\r\n    assertEquals(\"stash-plugin/Test.java\", diff3.getPath());\r\n    assertEquals(IssueType.CONTEXT, diff3.getType());\r\n    assertEquals(1, diff3.getComments().size());\r\n    assertFalse(diff3.containsComment(12345));\r\n    assertTrue(diff3.containsComment(54321));\r\n\r\n    StashComment comment2 = diff3.getComments().get(0);\r\n    assertEquals(54321, comment2.getId());\r\n    assertEquals(\"Test comment 2\", comment2.getMessage());\r\n    assertEquals(1, comment2.getVersion());\r\n\r\n    StashUser author2 = comment2.getAuthor();\r\n    assertEquals(54321, author2.getId());\r\n    assertEquals(\"SonarQube2\", author2.getName());\r\n    assertEquals(\"sonarqube2\", author2.getSlug());\r\n    assertEquals(\"sq2@email.com\", author2.getEmail());\r\n\r\n    StashDiff diff4 = report.getDiffs().get(3);\r\n    assertEquals((long)60, diff4.getSource());\r\n    assertEquals((long)70, diff4.getDestination());\r\n    assertEquals(\"stash-plugin/Test.java\", diff4.getPath());\r\n    assertEquals(IssueType.ADDED, diff4.getType());\r\n    assertEquals(0, diff4.getComments().size());\r\n    assertFalse(diff4.containsComment(12345));\r\n    assertFalse(diff4.containsComment(54321));\r\n  }\r\n\r\n  @Test\r\n  public void testExtractDiffsWithNoComments() throws Exception {\r\n    StashDiffReport report = StashCollector.extractDiffs(parse(DiffReportSample.baseReportWithNoComments));\r\n    assertEquals(4, report.getDiffs().size());\r\n\r\n    StashDiff diff1 = report.getDiffs().get(0);\r\n    assertEquals((long)10, diff1.getSource());\r\n    assertEquals((long)20, diff1.getDestination());\r\n    assertEquals(\"stash-plugin/Test.java\", diff1.getPath());\r\n    assertEquals(IssueType.CONTEXT, diff1.getType());\r\n    assertEquals(0, diff1.getComments().size());\r\n\r\n    StashDiff diff2 = report.getDiffs().get(1);\r\n    assertEquals((long)30, diff2.getSource());\r\n    assertEquals((long)40, diff2.getDestination());\r\n    assertEquals(\"stash-plugin/Test.java\", diff2.getPath());\r\n    assertEquals(IssueType.ADDED, diff2.getType());\r\n    assertEquals(0, diff2.getComments().size());\r\n\r\n    StashDiff diff3 = report.getDiffs().get(2);\r\n    assertEquals((long)40, diff3.getSource());\r\n    assertEquals((long)50, diff3.getDestination());\r\n    assertEquals(\"stash-plugin/Test.java\", diff3.getPath());\r\n    assertEquals(IssueType.CONTEXT, diff3.getType());\r\n    assertEquals(0, diff3.getComments().size());\r\n\r\n    StashDiff diff4 = report.getDiffs().get(3);\r\n    assertEquals((long)60, diff4.getSource());\r\n    assertEquals((long)70, diff4.getDestination());\r\n    assertEquals(\"stash-plugin/Test.java\", diff4.getPath());\r\n    assertEquals(IssueType.ADDED, diff4.getType());\r\n    assertEquals(0, diff4.getComments().size());\r\n  }\r\n\r\n  @Test\r\n  public void testExtractDiffsWithFileComments() throws Exception {\r\n    StashDiffReport report = StashCollector.extractDiffs(parse(DiffReportSample.baseReportWithFileComments));\r\n    assertEquals(5, report.getDiffs().size());\r\n\r\n    StashDiff diff1 = report.getDiffs().get(0);\r\n    assertEquals(1, diff1.getComments().size());\r\n    assertTrue(diff1.containsComment(12345));\r\n    assertFalse(diff1.containsComment(54321));\r\n\r\n    StashComment comment1 = diff1.getComments().get(0);\r\n    assertEquals(12345, comment1.getId());\r\n    assertEquals(\"Test comment\", comment1.getMessage());\r\n    assertEquals(1, comment1.getVersion());\r\n\r\n    StashUser author1 = comment1.getAuthor();\r\n    assertEquals(12345, author1.getId());\r\n    assertEquals(\"SonarQube\", author1.getName());\r\n    assertEquals(\"sonarqube\", author1.getSlug());\r\n    assertEquals(\"sq@email.com\", author1.getEmail());\r\n\r\n    StashDiff diff2 = report.getDiffs().get(1);\r\n    assertEquals(0, diff2.getComments().size());\r\n    assertFalse(diff2.containsComment(12345));\r\n    assertFalse(diff2.containsComment(54321));\r\n\r\n    StashDiff diff3 = report.getDiffs().get(2);\r\n    assertEquals(1, diff3.getComments().size());\r\n    assertFalse(diff3.containsComment(12345));\r\n    assertTrue(diff3.containsComment(54321));\r\n\r\n    StashComment comment2 = diff3.getComments().get(0);\r\n    assertEquals(54321, comment2.getId());\r\n    assertEquals(\"Test comment 2\", comment2.getMessage());\r\n    assertEquals(1, comment2.getVersion());\r\n\r\n    StashUser author2 = comment2.getAuthor();\r\n    assertEquals(54321, author2.getId());\r\n    assertEquals(\"SonarQube2\", author2.getName());\r\n    assertEquals(\"sonarqube2\", author2.getSlug());\r\n    assertEquals(\"sq2@email.com\", author2.getEmail());\r\n\r\n    StashDiff diff4 = report.getDiffs().get(3);\r\n    assertEquals(0, diff4.getComments().size());\r\n    assertFalse(diff4.containsComment(12345));\r\n    assertFalse(diff4.containsComment(54321));\r\n\r\n    StashDiff diff5 = report.getDiffs().get(4);\r\n    assertEquals(0, diff5.getSource());\r\n    assertEquals(0, diff5.getDestination());\r\n    assertEquals(\"stash-plugin/Test.java\", diff5.getPath());\r\n    assertEquals(IssueType.CONTEXT, diff5.getType());\r\n    assertEquals(2, diff5.getComments().size());\r\n    assertFalse(diff5.containsComment(12345));\r\n    assertFalse(diff5.containsComment(54321));\r\n    assertTrue(diff5.containsComment(123456));\r\n    assertTrue(diff5.containsComment(654321));\r\n\r\n    StashComment comment3 = diff5.getComments().get(0);\r\n    assertEquals(123456, comment3.getId());\r\n    assertEquals(1, comment3.getVersion());\r\n    assertEquals(\"Test File comment\", comment3.getMessage());\r\n\r\n    StashUser author3 = comment3.getAuthor();\r\n    assertEquals(12345, author3.getId());\r\n    assertEquals(\"SonarQube\", author3.getName());\r\n    assertEquals(\"sonarqube\", author3.getSlug());\r\n    assertEquals(\"sq@email.com\", author3.getEmail());\r\n\r\n    StashComment comment4 = diff5.getComments().get(1);\r\n    assertEquals(654321, comment4.getId());\r\n    assertEquals(\"Test File comment 2\", comment4.getMessage());\r\n    assertEquals(1, comment4.getVersion());\r\n\r\n    StashUser author4 = comment4.getAuthor();\r\n    assertEquals(54321, author4.getId());\r\n    assertEquals(\"SonarQube2\", author4.getName());\r\n    assertEquals(\"sonarqube2\", author4.getSlug());\r\n    assertEquals(\"sq2@email.com\", author4.getEmail());\r\n  }\r\n\r\n  @Test\r\n  public void testExtractDiffsWithEmptyFileComments() throws Exception {\r\n    StashDiffReport report = StashCollector.extractDiffs(parse(DiffReportSample.baseReportWithEmptyFileComments));\r\n    assertEquals(5, report.getDiffs().size());\r\n\r\n    StashDiff diff1 = report.getDiffs().get(0);\r\n    assertEquals(1, diff1.getComments().size());\r\n    assertTrue(diff1.containsComment(12345));\r\n    assertFalse(diff1.containsComment(54321));\r\n\r\n    StashComment comment1 = diff1.getComments().get(0);\r\n    assertEquals(12345, comment1.getId());\r\n    assertEquals(\"Test comment\", comment1.getMessage());\r\n    assertEquals(1, comment1.getVersion());\r\n\r\n    StashUser author1 = comment1.getAuthor();\r\n    assertEquals(12345, author1.getId());\r\n    assertEquals(\"SonarQube\", author1.getName());\r\n    assertEquals(\"sonarqube\", author1.getSlug());\r\n    assertEquals(\"sq@email.com\", author1.getEmail());\r\n\r\n    StashDiff diff2 = report.getDiffs().get(1);\r\n    assertEquals(0, diff2.getComments().size());\r\n    assertFalse(diff2.containsComment(12345));\r\n    assertFalse(diff2.containsComment(54321));\r\n\r\n    StashDiff diff3 = report.getDiffs().get(2);\r\n    assertEquals(1, diff3.getComments().size());\r\n    assertFalse(diff3.containsComment(12345));\r\n    assertTrue(diff3.containsComment(54321));\r\n\r\n    StashDiff diff4 = report.getDiffs().get(3);\r\n    assertEquals(0, diff4.getComments().size());\r\n    assertFalse(diff4.containsComment(12345));\r\n    assertFalse(diff4.containsComment(54321));\r\n\r\n    StashDiff diff5 = report.getDiffs().get(4);\r\n    assertEquals(0, diff5.getSource());\r\n    assertEquals(0, diff5.getDestination());\r\n    assertEquals(\"stash-plugin/Test.java\", diff5.getPath());\r\n    assertEquals(IssueType.CONTEXT, diff5.getType());\r\n    assertEquals(0, diff5.getComments().size());\r\n    assertFalse(diff5.containsComment(12345));\r\n    assertFalse(diff5.containsComment(54321));\r\n  }\r\n\r\n  @Test\r\n  public void testExtractDiffsWithEmptyReport() throws Exception {\r\n    String jsonBody = \"{ \\\"diffs\\\": []}\";\r\n\r\n    StashDiffReport report = StashCollector.extractDiffs(parse(jsonBody));\r\n    assertTrue(report.getDiffs().isEmpty());\r\n\r\n    report = StashCollector.extractDiffs(parse(DiffReportSample.emptyReport));\r\n    assertTrue(report.getDiffs().isEmpty());\r\n  }\r\n\r\n  @Test\r\n  public void testExtractDiffsWithMultipleFile() throws Exception {\r\n    StashDiffReport report = StashCollector.extractDiffs(parse(DiffReportSample.multipleFileReport));\r\n    assertEquals(2, report.getDiffs().size());\r\n\r\n    StashDiff diff1 = report.getDiffs().get(0);\r\n    assertEquals((long)10, diff1.getSource());\r\n    assertEquals((long)20, diff1.getDestination());\r\n    assertEquals(\"stash-plugin/Test.java\", diff1.getPath());\r\n    assertEquals(IssueType.CONTEXT, diff1.getType());\r\n    assertTrue(diff1.containsComment(12345));\r\n    assertFalse(diff1.containsComment(54321));\r\n\r\n    StashDiff diff2 = report.getDiffs().get(1);\r\n    assertEquals((long)20, diff2.getSource());\r\n    assertEquals((long)30, diff2.getDestination());\r\n    assertEquals(\"stash-plugin/Test1.java\", diff2.getPath());\r\n    assertEquals(IssueType.ADDED, diff2.getType());\r\n    assertFalse(diff2.containsComment(12345));\r\n    assertFalse(diff2.containsComment(54321));\r\n  }\r\n\r\n  @Test\r\n  public void testExtractDiffsWithDeletedFile() throws Exception {\r\n    StashDiffReport report = StashCollector.extractDiffs(parse(DiffReportSample.deletedFileReport));\r\n    assertEquals(2, report.getDiffs().size());\r\n\r\n    StashDiff diff1 = report.getDiffs().get(0);\r\n    assertEquals((long)10, diff1.getSource());\r\n    assertEquals((long)20, diff1.getDestination());\r\n    assertEquals(\"stash-plugin/Test2.java\", diff1.getPath());\r\n    assertEquals(IssueType.CONTEXT, diff1.getType());\r\n\r\n    StashDiff diff2 = report.getDiffs().get(1);\r\n    assertEquals((long)30, diff2.getSource());\r\n    assertEquals((long)40, diff2.getDestination());\r\n    assertEquals(\"stash-plugin/Test2.java\", diff2.getPath());\r\n    assertEquals(IssueType.ADDED, diff2.getType());\r\n  }\r\n\r\n  @Test\r\n  public void testExtractPullRequest() throws Exception {\r\n    String project = \"project\";\r\n    String repository = \"repository\";\r\n    int pullRequestId = 123;\r\n    long pullRequestVersion = 1;\r\n\r\n    long reviewerId = 1;\r\n    String reviewerName = \"SonarQube\";\r\n    String reviewerSlug = \"sonarqube\";\r\n    String reviewerEmail = \"sq@email.com\";\r\n\r\n    String jsonBody = \"{\\\"id\\\": \"\r\n                      + pullRequestId\r\n                      + \", \\\"version\\\": \"\r\n                      + pullRequestVersion\r\n                      + \", \\\"title\\\": \\\"PR-Test\\\",\"\r\n                      + \"\\\"description\\\": \\\"PR-test\\\", \\\"reviewers\\\": [\"\r\n                      + \"{\\\"user\\\": { \\\"name\\\":\\\"\"\r\n                      + reviewerName\r\n                      + \"\\\", \\\"emailAddress\\\": \\\"\"\r\n                      + reviewerEmail\r\n                      + \"\\\",\"\r\n                      + \"\\\"id\\\": \"\r\n                      + reviewerId\r\n                      + \", \\\"slug\\\": \\\"\"\r\n                      + reviewerSlug\r\n                      + \"\\\"}, \\\"role\\\": \\\"REVIEWER\\\", \\\"approved\\\": false}]}\";\r\n\r\n    StashPullRequest pullRequest = StashCollector.extractPullRequest(pr, parse(jsonBody));\r\n\r\n    assertEquals(project, pullRequest.getProject());\r\n    assertEquals(repository, pullRequest.getRepository());\r\n    assertEquals(pullRequestId, pullRequest.getId());\r\n    assertEquals(pullRequestVersion, pullRequest.getVersion());\r\n\r\n    StashUser reviewer = new StashUser(reviewerId, reviewerName, reviewerSlug, reviewerEmail);\r\n    assertEquals(1, pullRequest.getReviewers().size());\r\n    assertTrue(pullRequest.containsReviewer(reviewer));\r\n  }\r\n\r\n  @Test\r\n  public void testExtractPullRequestWithSeveralReviewer() throws Exception {\r\n    String project = \"project\";\r\n    String repository = \"repository\";\r\n    int pullRequestId = 123;\r\n    long pullRequestVersion = 1;\r\n\r\n    long reviewerId1 = 1;\r\n    String reviewerName1 = \"SonarQube1\";\r\n    String reviewerSlug1 = \"sonarqube1\";\r\n    String reviewerEmail1 = \"sq1@email.com\";\r\n\r\n    long reviewerId2 = 1;\r\n    String reviewerName2 = \"SonarQube2\";\r\n    String reviewerSlug2 = \"sonarqube2\";\r\n    String reviewerEmail2 = \"sq2@email.com\";\r\n\r\n    String jsonBody = \"{\\\"id\\\": \"\r\n                      + pullRequestId\r\n                      + \", \\\"version\\\": \"\r\n                      + pullRequestVersion\r\n                      + \", \\\"title\\\": \\\"PR-Test\\\",\"\r\n                      + \"\\\"description\\\": \\\"PR-test\\\", \\\"reviewers\\\": [\"\r\n                      + \"{\\\"user\\\": { \\\"name\\\":\\\"\"\r\n                      + reviewerName1\r\n                      + \"\\\", \\\"emailAddress\\\": \\\"\"\r\n                      + reviewerEmail1\r\n                      + \"\\\",\"\r\n                      + \"\\\"id\\\": \"\r\n                      + reviewerId1\r\n                      + \", \\\"slug\\\": \\\"\"\r\n                      + reviewerSlug1\r\n                      + \"\\\"}, \\\"role\\\": \\\"REVIEWER\\\", \\\"approved\\\": false},\"\r\n                      + \"{\\\"user\\\": { \\\"name\\\":\\\"\"\r\n                      + reviewerName2\r\n                      + \"\\\", \\\"emailAddress\\\": \\\"\"\r\n                      + reviewerEmail2\r\n                      + \"\\\",\"\r\n                      + \"\\\"id\\\": \"\r\n                      + reviewerId2\r\n                      + \", \\\"slug\\\": \\\"\"\r\n                      + reviewerSlug2\r\n                      + \"\\\"}, \\\"role\\\": \\\"REVIEWER\\\", \\\"approved\\\": false}]}\";\r\n\r\n    StashPullRequest pullRequest = StashCollector.extractPullRequest(pr, parse(jsonBody));\r\n\r\n    assertEquals(project, pullRequest.getProject());\r\n    assertEquals(repository, pullRequest.getRepository());\r\n    assertEquals(pullRequestId, pullRequest.getId());\r\n    assertEquals(pullRequestVersion, pullRequest.getVersion());\r\n\r\n    StashUser reviewer1 = new StashUser(reviewerId1, reviewerName1, reviewerSlug1, reviewerEmail1);\r\n    StashUser reviewer2 = new StashUser(reviewerId2, reviewerName2, reviewerSlug2, reviewerEmail2);\r\n    assertEquals(2, pullRequest.getReviewers().size());\r\n    assertTrue(pullRequest.containsReviewer(reviewer1));\r\n    assertTrue(pullRequest.containsReviewer(reviewer2));\r\n  }\r\n\r\n  @Test\r\n  public void testExtractPullRequestWithNoReviewer() throws Exception {\r\n    String project = \"project\";\r\n    String repository = \"repository\";\r\n    int pullRequestId = 123;\r\n    long pullRequestVersion = 1;\r\n\r\n    String jsonBody = \"{\\\"id\\\": \" + pullRequestId + \", \\\"version\\\": \" + pullRequestVersion + \", \\\"title\\\": \\\"PR-Test\\\",\"\r\n                      + \"\\\"description\\\": \\\"PR-test\\\", \\\"reviewers\\\": []}\";\r\n\r\n    StashPullRequest pullRequest = StashCollector.extractPullRequest(pr, parse(jsonBody));\r\n\r\n    assertEquals(project, pullRequest.getProject());\r\n    assertEquals(repository, pullRequest.getRepository());\r\n    assertEquals(pullRequestId, pullRequest.getId());\r\n    assertEquals(pullRequestVersion, pullRequest.getVersion());\r\n\r\n    assertEquals(0, pullRequest.getReviewers().size());\r\n  }\r\n\r\n  @Test\r\n  public void testExtractUser() throws Exception {\r\n    long userId = 1;\r\n    String userName = \"SonarQube\";\r\n    String userSlug = \"sonarqube\";\r\n    String userEmail = \"sq@email.com\";\r\n\r\n    String jsonBody = \"{ \\\"name\\\":\\\"\" + userName + \"\\\", \\\"email\\\": \\\"\" + userEmail + \"\\\",\"\r\n                      + \"\\\"id\\\": \" + userId + \", \\\"slug\\\": \\\"\" + userSlug + \"\\\"}\";\r\n\r\n    StashUser user = StashCollector.extractUser(parse(jsonBody));\r\n    assertEquals(userId, user.getId());\r\n    assertEquals(userName, user.getName());\r\n    assertEquals(userSlug, user.getSlug());\r\n    assertEquals(userEmail, user.getEmail());\r\n  }\r\n\r\n  @Test\r\n  public void testExtractTask() throws Exception {\r\n    long id = 1111;\r\n    String text = \"Text\";\r\n    String state = \"State\";\r\n    boolean deletable = true;\r\n\r\n    String jsonTask = \"{ \\\"id\\\":\" + id + \", \\\"text\\\":\\\"\" + text + \"\\\", \\\"state\\\":\\\"\" + state + \"\\\",\"\r\n                      + \"\\\"permittedOperations\\\": { \\\"deletable\\\":\" + deletable + \"}}\";\r\n\r\n    StashTask task = StashCollector.extractTask(parse(jsonTask));\r\n\r\n    assertEquals(id, (long)task.getId());\r\n    assertEquals(text, task.getText());\r\n    assertEquals(state, task.getState());\r\n    assertEquals(deletable, task.isDeletable());\r\n  }\r\n\r\n  @Test\r\n  public void testExtractTaskWithoutPermittedOperation() throws Exception {\r\n    long id = 1111;\r\n    String text = \"Text\";\r\n    String state = \"State\";\r\n\r\n    String jsonTask = \"{ \\\"id\\\":\" + id + \", \\\"text\\\":\\\"\" + text + \"\\\", \\\"state\\\": \\\"\" + state + \"\\\"}\";\r\n\r\n    StashTask task = StashCollector.extractTask(parse(jsonTask));\r\n\r\n    assertEquals(id, (long)task.getId());\r\n    assertEquals(text, task.getText());\r\n    assertEquals(state, task.getState());\r\n    assertTrue(task.isDeletable());\r\n  }\r\n\r\n  private static JsonObject parse(String s) throws Exception {\r\n    return (JsonObject) Jsoner.deserialize(s);\r\n  }\r\n}\r\n"
  },
  {
    "path": "src/test/resources/fixtures/issue194_stash_diff.json",
    "content": "{\n    \"fromHash\": \"820a8e5219b4ebdf44060f8db5a19893abf5360c\",\n    \"toHash\": \"7424a87f33d9665ed7a9b6800a2ad7926d10715b\",\n    \"contextLines\": 10,\n    \"whitespace\": \"SHOW\",\n    \"diffs\": [\n        {\n            \"source\": {\n                \"components\": [\n                    \"aModule-api-app\",\n                    \"pom.xml\"\n                ],\n                \"parent\": \"aModule-api-app\",\n                \"name\": \"pom.xml\",\n                \"extension\": \"xml\",\n                \"toString\": \"aModule-api-app/pom.xml\"\n            },\n            \"destination\": {\n                \"components\": [\n                    \"aModule-api-app\",\n                    \"pom.xml\"\n                ],\n                \"parent\": \"aModule-api-app\",\n                \"name\": \"pom.xml\",\n                \"extension\": \"xml\",\n                \"toString\": \"aModule-api-app/pom.xml\"\n            },\n            \"hunks\": [\n                {\n                    \"sourceLine\": 1,\n                    \"sourceSpan\": 16,\n                    \"destinationLine\": 1,\n                    \"destinationSpan\": 16,\n                    \"segments\": [\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 1,\n                                    \"destination\": 1,\n                                    \"line\": \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 2,\n                                    \"destination\": 2,\n                                    \"line\": \"<project xmlns=\\\"http://maven.apache.org/POM/4.0.0\\\" xmlns:xsi=\\\"http://www.w3.org/2001/XMLSchema-instance\\\" xsi:schemaLocation=\\\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\\\">\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 3,\n                                    \"destination\": 3,\n                                    \"line\": \"  <parent>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 4,\n                                    \"destination\": 4,\n                                    \"line\": \"    <groupId>com.gdn.package</groupId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 5,\n                                    \"destination\": 5,\n                                    \"line\": \"    <artifactId>aModule</artifactId>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"REMOVED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 6,\n                                    \"destination\": 6,\n                                    \"line\": \"    <version>0.0.1-4-SNAPSHOT</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"ADDED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 7,\n                                    \"destination\": 6,\n                                    \"line\": \"    <version>0.0.1-5-SNAPSHOT</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 7,\n                                    \"destination\": 7,\n                                    \"line\": \"  </parent>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 8,\n                                    \"destination\": 8,\n                                    \"line\": \"  <modelVersion>4.0.0</modelVersion>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 9,\n                                    \"destination\": 9,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 10,\n                                    \"destination\": 10,\n                                    \"line\": \"  <artifactId>aModule-api-app</artifactId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 11,\n                                    \"destination\": 11,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 12,\n                                    \"destination\": 12,\n                                    \"line\": \"  <dependencies>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 13,\n                                    \"destination\": 13,\n                                    \"line\": \"    <dependency>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 14,\n                                    \"destination\": 14,\n                                    \"line\": \"      <groupId>com.gdn.package</groupId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 15,\n                                    \"destination\": 15,\n                                    \"line\": \"      <artifactId>aModule-api-web</artifactId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 16,\n                                    \"destination\": 16,\n                                    \"line\": \"      <version>${project.version}</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        }\n                    ],\n                    \"truncated\": false\n                }\n            ],\n            \"truncated\": false,\n            \"lineComments\": [\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 71,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Remove this unused \\\"B\\\" local variable. [[squid:S1481](http://10.177.92.24:9000/coding_rules#rule_key=squid:S1481)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686764,\n                    \"updatedDate\": 1542790686764,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 72,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'. [[squid:S00117](http://10.177.92.24:9000/coding_rules#rule_key=squid:S00117)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686785,\n                    \"updatedDate\": 1542790686785,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 70,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Change this condition so that it does not always evaluate to \\\"false\\\" [[squid:S2583](http://10.177.92.24:9000/coding_rules#rule_key=squid:S2583)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686749,\n                    \"updatedDate\": 1542790686749,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 68,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Replace this use of System.out or System.err by a logger. [[squid:S106](http://10.177.92.24:9000/coding_rules#rule_key=squid:S106)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686696,\n                    \"updatedDate\": 1542790686696,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 73,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'. [[squid:S00117](http://10.177.92.24:9000/coding_rules#rule_key=squid:S00117)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686806,\n                    \"updatedDate\": 1542790686806,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 69,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Replace this use of System.out or System.err by a logger. [[squid:S106](http://10.177.92.24:9000/coding_rules#rule_key=squid:S106)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686731,\n                    \"updatedDate\": 1542790686731,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                }\n            ]\n        },\n        {\n            \"source\": {\n                \"components\": [\n                    \"aModule-api-app\",\n                    \"src\",\n                    \"main\",\n                    \"resources\",\n                    \"logback.xml\"\n                ],\n                \"parent\": \"aModule-api-app/src/main/resources\",\n                \"name\": \"logback.xml\",\n                \"extension\": \"xml\",\n                \"toString\": \"aModule-api-app/src/main/resources/logback.xml\"\n            },\n            \"destination\": {\n                \"components\": [\n                    \"aModule-api-app\",\n                    \"src\",\n                    \"main\",\n                    \"resources\",\n                    \"logback.xml\"\n                ],\n                \"parent\": \"aModule-api-app/src/main/resources\",\n                \"name\": \"logback.xml\",\n                \"extension\": \"xml\",\n                \"toString\": \"aModule-api-app/src/main/resources/logback.xml\"\n            },\n            \"hunks\": [\n                {\n                    \"sourceLine\": 41,\n                    \"sourceSpan\": 24,\n                    \"destinationLine\": 41,\n                    \"destinationSpan\": 24,\n                    \"segments\": [\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 41,\n                                    \"destination\": 41,\n                                    \"line\": \"  </appender>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 42,\n                                    \"destination\": 42,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 43,\n                                    \"destination\": 43,\n                                    \"line\": \"  <appender name=\\\"async\\\" class=\\\"ch.qos.logback.classic.AsyncAppender\\\">\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 44,\n                                    \"destination\": 44,\n                                    \"line\": \"    <appender-ref ref=\\\"accessLog\\\" />\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 45,\n                                    \"destination\": 45,\n                                    \"line\": \"  </appender>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 46,\n                                    \"destination\": 46,\n                                    \"line\": \"  <logger name=\\\"reactor.netty.http.server.AccessLog\\\" level=\\\"INFO\\\" additivity=\\\"false\\\">\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 47,\n                                    \"destination\": 47,\n                                    \"line\": \"    <appender-ref ref=\\\"async\\\"/>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 48,\n                                    \"destination\": 48,\n                                    \"line\": \"  </logger>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 49,\n                                    \"destination\": 49,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 50,\n                                    \"destination\": 50,\n                                    \"line\": \"  <!--FOR DEVELOPMENT PLEASE UNCOMMENT THIS, NEVER PUSH IF YOU UNCOMMENT THIS -->\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"REMOVED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 51,\n                                    \"destination\": 51,\n                                    \"line\": \"  <!--<appender name=\\\"CONSOLE\\\" class=\\\"ch.qos.logback.core.ConsoleAppender\\\">-->\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 52,\n                                    \"destination\": 51,\n                                    \"line\": \"    <!--<encoder>-->\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 53,\n                                    \"destination\": 51,\n                                    \"line\": \"      <!--<pattern>${CONSOLE_LOG_PATTERN:-%clr([%date{\\\"yyyy-MM-dd'T'HH:mm:ss,SSSXXX\\\", GMT+07:00}]){faint}%clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(-&#45;&#45;){faint}%clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint}%m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}</pattern>-->\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 54,\n                                    \"destination\": 51,\n                                    \"line\": \"      <!--<charset>utf8</charset>-->\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 55,\n                                    \"destination\": 51,\n                                    \"line\": \"    <!--</encoder>-->\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 56,\n                                    \"destination\": 51,\n                                    \"line\": \"  <!--</appender>-->\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"ADDED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 57,\n                                    \"destination\": 51,\n                                    \"line\": \"  <appender name=\\\"CONSOLE\\\" class=\\\"ch.qos.logback.core.ConsoleAppender\\\">\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 57,\n                                    \"destination\": 52,\n                                    \"line\": \"    <encoder>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 57,\n                                    \"destination\": 53,\n                                    \"line\": \"      <pattern>${CONSOLE_LOG_PATTERN:-%clr([%date{\\\"yyyy-MM-dd'T'HH:mm:ss,SSSXXX\\\", GMT+07:00}]){faint}%clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint}%clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint}%m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}</pattern>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 57,\n                                    \"destination\": 54,\n                                    \"line\": \"      <charset>utf8</charset>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 57,\n                                    \"destination\": 55,\n                                    \"line\": \"    </encoder>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 57,\n                                    \"destination\": 56,\n                                    \"line\": \"  </appender>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 57,\n                                    \"destination\": 57,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 58,\n                                    \"destination\": 58,\n                                    \"line\": \"  <root level=\\\"INFO\\\">\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 59,\n                                    \"destination\": 59,\n                                    \"line\": \"    <!--FOR DEVELOPMENT PLEASE UNCOMMENT THIS, NEVER PUSH IF YOU UNCOMMENT THIS -->\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"REMOVED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 60,\n                                    \"destination\": 60,\n                                    \"line\": \"    <!--<appender-ref ref=\\\"CONSOLE\\\"/>-->\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"ADDED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 61,\n                                    \"destination\": 60,\n                                    \"line\": \"    <appender-ref ref=\\\"CONSOLE\\\"/>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 61,\n                                    \"destination\": 61,\n                                    \"line\": \"    <appender-ref ref=\\\"FILE\\\"/>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 62,\n                                    \"destination\": 62,\n                                    \"line\": \"  </root>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 63,\n                                    \"destination\": 63,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 64,\n                                    \"destination\": 64,\n                                    \"line\": \"</configuration>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        }\n                    ],\n                    \"truncated\": false\n                }\n            ],\n            \"truncated\": false,\n            \"lineComments\": [\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 71,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Remove this unused \\\"B\\\" local variable. [[squid:S1481](http://10.177.92.24:9000/coding_rules#rule_key=squid:S1481)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686764,\n                    \"updatedDate\": 1542790686764,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 72,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'. [[squid:S00117](http://10.177.92.24:9000/coding_rules#rule_key=squid:S00117)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686785,\n                    \"updatedDate\": 1542790686785,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 70,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Change this condition so that it does not always evaluate to \\\"false\\\" [[squid:S2583](http://10.177.92.24:9000/coding_rules#rule_key=squid:S2583)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686749,\n                    \"updatedDate\": 1542790686749,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 68,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Replace this use of System.out or System.err by a logger. [[squid:S106](http://10.177.92.24:9000/coding_rules#rule_key=squid:S106)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686696,\n                    \"updatedDate\": 1542790686696,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 73,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'. [[squid:S00117](http://10.177.92.24:9000/coding_rules#rule_key=squid:S00117)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686806,\n                    \"updatedDate\": 1542790686806,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 69,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Replace this use of System.out or System.err by a logger. [[squid:S106](http://10.177.92.24:9000/coding_rules#rule_key=squid:S106)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686731,\n                    \"updatedDate\": 1542790686731,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                }\n            ]\n        },\n        {\n            \"source\": {\n                \"components\": [\n                    \"aModule-api-client-impl\",\n                    \"pom.xml\"\n                ],\n                \"parent\": \"aModule-api-client-impl\",\n                \"name\": \"pom.xml\",\n                \"extension\": \"xml\",\n                \"toString\": \"aModule-api-client-impl/pom.xml\"\n            },\n            \"destination\": {\n                \"components\": [\n                    \"aModule-api-client-impl\",\n                    \"pom.xml\"\n                ],\n                \"parent\": \"aModule-api-client-impl\",\n                \"name\": \"pom.xml\",\n                \"extension\": \"xml\",\n                \"toString\": \"aModule-api-client-impl/pom.xml\"\n            },\n            \"hunks\": [\n                {\n                    \"sourceLine\": 1,\n                    \"sourceSpan\": 16,\n                    \"destinationLine\": 1,\n                    \"destinationSpan\": 16,\n                    \"segments\": [\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 1,\n                                    \"destination\": 1,\n                                    \"line\": \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 2,\n                                    \"destination\": 2,\n                                    \"line\": \"<project xmlns=\\\"http://maven.apache.org/POM/4.0.0\\\" xmlns:xsi=\\\"http://www.w3.org/2001/XMLSchema-instance\\\" xsi:schemaLocation=\\\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\\\">\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 3,\n                                    \"destination\": 3,\n                                    \"line\": \"  <parent>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 4,\n                                    \"destination\": 4,\n                                    \"line\": \"    <groupId>com.gdn.package</groupId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 5,\n                                    \"destination\": 5,\n                                    \"line\": \"    <artifactId>aModule</artifactId>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"REMOVED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 6,\n                                    \"destination\": 6,\n                                    \"line\": \"    <version>0.0.1-4-SNAPSHOT</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"ADDED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 7,\n                                    \"destination\": 6,\n                                    \"line\": \"    <version>0.0.1-5-SNAPSHOT</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 7,\n                                    \"destination\": 7,\n                                    \"line\": \"  </parent>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 8,\n                                    \"destination\": 8,\n                                    \"line\": \"  <modelVersion>4.0.0</modelVersion>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 9,\n                                    \"destination\": 9,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 10,\n                                    \"destination\": 10,\n                                    \"line\": \"  <artifactId>aModule-api-client-impl</artifactId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 11,\n                                    \"destination\": 11,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 12,\n                                    \"destination\": 12,\n                                    \"line\": \"  <dependencies>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 13,\n                                    \"destination\": 13,\n                                    \"line\": \"    <dependency>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 14,\n                                    \"destination\": 14,\n                                    \"line\": \"      <groupId>com.gdn.package</groupId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 15,\n                                    \"destination\": 15,\n                                    \"line\": \"      <artifactId>aModule-api-properties</artifactId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 16,\n                                    \"destination\": 16,\n                                    \"line\": \"      <version>${project.version}</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        }\n                    ],\n                    \"truncated\": false\n                },\n                {\n                    \"sourceLine\": 41,\n                    \"sourceSpan\": 11,\n                    \"destinationLine\": 41,\n                    \"destinationSpan\": 11,\n                    \"segments\": [\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 41,\n                                    \"destination\": 41,\n                                    \"line\": \"      <artifactId>wiremock-standalone</artifactId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 42,\n                                    \"destination\": 42,\n                                    \"line\": \"      <scope>test</scope>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 43,\n                                    \"destination\": 43,\n                                    \"line\": \"    </dependency>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 44,\n                                    \"destination\": 44,\n                                    \"line\": \"    <dependency>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 45,\n                                    \"destination\": 45,\n                                    \"line\": \"      <groupId>io.rest-assured</groupId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 46,\n                                    \"destination\": 46,\n                                    \"line\": \"      <artifactId>rest-assured</artifactId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 47,\n                                    \"destination\": 47,\n                                    \"line\": \"      <scope>test</scope>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 48,\n                                    \"destination\": 48,\n                                    \"line\": \"    </dependency>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 49,\n                                    \"destination\": 49,\n                                    \"line\": \"  </dependencies>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 50,\n                                    \"destination\": 50,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"REMOVED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 51,\n                                    \"destination\": 51,\n                                    \"line\": \"</project>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"ADDED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 52,\n                                    \"destination\": 51,\n                                    \"line\": \"</project>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        }\n                    ],\n                    \"truncated\": false\n                }\n            ],\n            \"truncated\": false,\n            \"lineComments\": [\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 71,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Remove this unused \\\"B\\\" local variable. [[squid:S1481](http://10.177.92.24:9000/coding_rules#rule_key=squid:S1481)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686764,\n                    \"updatedDate\": 1542790686764,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 72,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'. [[squid:S00117](http://10.177.92.24:9000/coding_rules#rule_key=squid:S00117)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686785,\n                    \"updatedDate\": 1542790686785,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 70,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Change this condition so that it does not always evaluate to \\\"false\\\" [[squid:S2583](http://10.177.92.24:9000/coding_rules#rule_key=squid:S2583)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686749,\n                    \"updatedDate\": 1542790686749,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 68,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Replace this use of System.out or System.err by a logger. [[squid:S106](http://10.177.92.24:9000/coding_rules#rule_key=squid:S106)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686696,\n                    \"updatedDate\": 1542790686696,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 73,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'. [[squid:S00117](http://10.177.92.24:9000/coding_rules#rule_key=squid:S00117)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686806,\n                    \"updatedDate\": 1542790686806,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 69,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Replace this use of System.out or System.err by a logger. [[squid:S106](http://10.177.92.24:9000/coding_rules#rule_key=squid:S106)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686731,\n                    \"updatedDate\": 1542790686731,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                }\n            ]\n        },\n        {\n            \"source\": {\n                \"components\": [\n                    \"aModule-api-client-model\",\n                    \"pom.xml\"\n                ],\n                \"parent\": \"aModule-api-client-model\",\n                \"name\": \"pom.xml\",\n                \"extension\": \"xml\",\n                \"toString\": \"aModule-api-client-model/pom.xml\"\n            },\n            \"destination\": {\n                \"components\": [\n                    \"aModule-api-client-model\",\n                    \"pom.xml\"\n                ],\n                \"parent\": \"aModule-api-client-model\",\n                \"name\": \"pom.xml\",\n                \"extension\": \"xml\",\n                \"toString\": \"aModule-api-client-model/pom.xml\"\n            },\n            \"hunks\": [\n                {\n                    \"sourceLine\": 1,\n                    \"sourceSpan\": 16,\n                    \"destinationLine\": 1,\n                    \"destinationSpan\": 16,\n                    \"segments\": [\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 1,\n                                    \"destination\": 1,\n                                    \"line\": \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 2,\n                                    \"destination\": 2,\n                                    \"line\": \"<project xmlns=\\\"http://maven.apache.org/POM/4.0.0\\\" xmlns:xsi=\\\"http://www.w3.org/2001/XMLSchema-instance\\\" xsi:schemaLocation=\\\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\\\">\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 3,\n                                    \"destination\": 3,\n                                    \"line\": \"  <parent>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 4,\n                                    \"destination\": 4,\n                                    \"line\": \"    <groupId>com.gdn.package</groupId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 5,\n                                    \"destination\": 5,\n                                    \"line\": \"    <artifactId>aModule</artifactId>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"REMOVED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 6,\n                                    \"destination\": 6,\n                                    \"line\": \"    <version>0.0.1-4-SNAPSHOT</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"ADDED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 7,\n                                    \"destination\": 6,\n                                    \"line\": \"    <version>0.0.1-5-SNAPSHOT</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 7,\n                                    \"destination\": 7,\n                                    \"line\": \"  </parent>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 8,\n                                    \"destination\": 8,\n                                    \"line\": \"  <modelVersion>4.0.0</modelVersion>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 9,\n                                    \"destination\": 9,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 10,\n                                    \"destination\": 10,\n                                    \"line\": \"  <artifactId>aModule-api-client-model</artifactId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 11,\n                                    \"destination\": 11,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 12,\n                                    \"destination\": 12,\n                                    \"line\": \"  <dependencies>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 13,\n                                    \"destination\": 13,\n                                    \"line\": \"    <dependency>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 14,\n                                    \"destination\": 14,\n                                    \"line\": \"      <groupId>com.gdn.package</groupId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 15,\n                                    \"destination\": 15,\n                                    \"line\": \"      <artifactId>aModule-api-entity</artifactId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 16,\n                                    \"destination\": 16,\n                                    \"line\": \"      <version>${project.version}</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        }\n                    ],\n                    \"truncated\": false\n                }\n            ],\n            \"truncated\": false,\n            \"lineComments\": [\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 71,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Remove this unused \\\"B\\\" local variable. [[squid:S1481](http://10.177.92.24:9000/coding_rules#rule_key=squid:S1481)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686764,\n                    \"updatedDate\": 1542790686764,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 72,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'. [[squid:S00117](http://10.177.92.24:9000/coding_rules#rule_key=squid:S00117)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686785,\n                    \"updatedDate\": 1542790686785,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 70,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Change this condition so that it does not always evaluate to \\\"false\\\" [[squid:S2583](http://10.177.92.24:9000/coding_rules#rule_key=squid:S2583)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686749,\n                    \"updatedDate\": 1542790686749,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 68,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Replace this use of System.out or System.err by a logger. [[squid:S106](http://10.177.92.24:9000/coding_rules#rule_key=squid:S106)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686696,\n                    \"updatedDate\": 1542790686696,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 73,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'. [[squid:S00117](http://10.177.92.24:9000/coding_rules#rule_key=squid:S00117)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686806,\n                    \"updatedDate\": 1542790686806,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 69,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Replace this use of System.out or System.err by a logger. [[squid:S106](http://10.177.92.24:9000/coding_rules#rule_key=squid:S106)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686731,\n                    \"updatedDate\": 1542790686731,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                }\n            ]\n        },\n        {\n            \"source\": {\n                \"components\": [\n                    \"aModule-api-client\",\n                    \"pom.xml\"\n                ],\n                \"parent\": \"aModule-api-client\",\n                \"name\": \"pom.xml\",\n                \"extension\": \"xml\",\n                \"toString\": \"aModule-api-client/pom.xml\"\n            },\n            \"destination\": {\n                \"components\": [\n                    \"aModule-api-client\",\n                    \"pom.xml\"\n                ],\n                \"parent\": \"aModule-api-client\",\n                \"name\": \"pom.xml\",\n                \"extension\": \"xml\",\n                \"toString\": \"aModule-api-client/pom.xml\"\n            },\n            \"hunks\": [\n                {\n                    \"sourceLine\": 1,\n                    \"sourceSpan\": 16,\n                    \"destinationLine\": 1,\n                    \"destinationSpan\": 16,\n                    \"segments\": [\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 1,\n                                    \"destination\": 1,\n                                    \"line\": \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 2,\n                                    \"destination\": 2,\n                                    \"line\": \"<project xmlns=\\\"http://maven.apache.org/POM/4.0.0\\\" xmlns:xsi=\\\"http://www.w3.org/2001/XMLSchema-instance\\\" xsi:schemaLocation=\\\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\\\">\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 3,\n                                    \"destination\": 3,\n                                    \"line\": \"  <parent>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 4,\n                                    \"destination\": 4,\n                                    \"line\": \"    <groupId>com.gdn.package</groupId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 5,\n                                    \"destination\": 5,\n                                    \"line\": \"    <artifactId>aModule</artifactId>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"REMOVED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 6,\n                                    \"destination\": 6,\n                                    \"line\": \"    <version>0.0.1-4-SNAPSHOT</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"ADDED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 7,\n                                    \"destination\": 6,\n                                    \"line\": \"    <version>0.0.1-5-SNAPSHOT</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 7,\n                                    \"destination\": 7,\n                                    \"line\": \"  </parent>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 8,\n                                    \"destination\": 8,\n                                    \"line\": \"  <modelVersion>4.0.0</modelVersion>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 9,\n                                    \"destination\": 9,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 10,\n                                    \"destination\": 10,\n                                    \"line\": \"  <artifactId>aModule-api-client</artifactId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 11,\n                                    \"destination\": 11,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 12,\n                                    \"destination\": 12,\n                                    \"line\": \"  <dependencies>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 13,\n                                    \"destination\": 13,\n                                    \"line\": \"    <dependency>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 14,\n                                    \"destination\": 14,\n                                    \"line\": \"      <groupId>com.gdn.package</groupId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 15,\n                                    \"destination\": 15,\n                                    \"line\": \"      <artifactId>aModule-api-properties</artifactId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 16,\n                                    \"destination\": 16,\n                                    \"line\": \"      <version>${project.version}</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        }\n                    ],\n                    \"truncated\": false\n                }\n            ],\n            \"truncated\": false,\n            \"lineComments\": [\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 71,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Remove this unused \\\"B\\\" local variable. [[squid:S1481](http://10.177.92.24:9000/coding_rules#rule_key=squid:S1481)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686764,\n                    \"updatedDate\": 1542790686764,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 72,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'. [[squid:S00117](http://10.177.92.24:9000/coding_rules#rule_key=squid:S00117)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686785,\n                    \"updatedDate\": 1542790686785,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 70,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Change this condition so that it does not always evaluate to \\\"false\\\" [[squid:S2583](http://10.177.92.24:9000/coding_rules#rule_key=squid:S2583)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686749,\n                    \"updatedDate\": 1542790686749,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 68,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Replace this use of System.out or System.err by a logger. [[squid:S106](http://10.177.92.24:9000/coding_rules#rule_key=squid:S106)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686696,\n                    \"updatedDate\": 1542790686696,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 73,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'. [[squid:S00117](http://10.177.92.24:9000/coding_rules#rule_key=squid:S00117)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686806,\n                    \"updatedDate\": 1542790686806,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 69,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Replace this use of System.out or System.err by a logger. [[squid:S106](http://10.177.92.24:9000/coding_rules#rule_key=squid:S106)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686731,\n                    \"updatedDate\": 1542790686731,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                }\n            ]\n        },\n        {\n            \"source\": {\n                \"components\": [\n                    \"aModule-api-client\",\n                    \"src\",\n                    \"main\",\n                    \"java\",\n                    \"com\",\n                    \"gdn\",\n                    \"package\",\n                    \"aModule\",\n                    \"client\",\n                    \"aModuleClient.java\"\n                ],\n                \"parent\": \"aModule-api-client/src/main/java/com/gdn/package/aModule/client\",\n                \"name\": \"aModuleClient.java\",\n                \"extension\": \"java\",\n                \"toString\": \"aModule-api-client/src/main/java/com/gdn/package/aModule/client/aModuleClient.java\"\n            },\n            \"destination\": {\n                \"components\": [\n                    \"aModule-api-client\",\n                    \"src\",\n                    \"main\",\n                    \"java\",\n                    \"com\",\n                    \"gdn\",\n                    \"package\",\n                    \"aModule\",\n                    \"client\",\n                    \"aModuleClient.java\"\n                ],\n                \"parent\": \"aModule-api-client/src/main/java/com/gdn/package/aModule/client\",\n                \"name\": \"aModuleClient.java\",\n                \"extension\": \"java\",\n                \"toString\": \"aModule-api-client/src/main/java/com/gdn/package/aModule/client/aModuleClient.java\"\n            },\n            \"hunks\": [\n                {\n                    \"context\": \"public class aModuleClient implements NettyConnector<aModuleClientResponse, aModuleClientReq\",\n                    \"sourceLine\": 95,\n                    \"sourceSpan\": 28,\n                    \"destinationLine\": 95,\n                    \"destinationSpan\": 37,\n                    \"segments\": [\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 95,\n                                    \"destination\": 95,\n                                    \"line\": \"        }\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 96,\n                                    \"destination\": 96,\n                                    \"line\": \"        if (!clientBuilder.isPoolAvailable() && !clientBuilder.isPoolDisabled()) {\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 97,\n                                    \"destination\": 97,\n                                    \"line\": \"            clientBuilder.poolResources(aModuleResources.get());\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 98,\n                                    \"destination\": 98,\n                                    \"line\": \"        }\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 99,\n                                    \"destination\": 99,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 100,\n                                    \"destination\": 100,\n                                    \"line\": \"        this.headerLength = headerLength;\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 101,\n                                    \"destination\": 101,\n                                    \"line\": \"        this.encoder = encoder;\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 102,\n                                    \"destination\": 102,\n                                    \"line\": \"        this.decoder = decoder;\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 103,\n                                    \"destination\": 103,\n                                    \"line\": \"        this.options = clientBuilder.build();\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 104,\n                                    \"destination\": 104,\n                                    \"line\": \"        this.bridgeClient = new TcpBridgeClient(this.options);\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"ADDED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 105,\n                                    \"destination\": 105,\n                                    \"line\": \"        int a = 4;\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 105,\n                                    \"destination\": 106,\n                                    \"line\": \"        Boolean B = false;\",\n                                    \"truncated\": false,\n                                    \"commentIds\": [\n                                        71,\n                                        72\n                                    ]\n                                },\n                                {\n                                    \"source\": 105,\n                                    \"destination\": 107,\n                                    \"line\": \"        if\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 105,\n                                    \"destination\": 108,\n                                    \"line\": \"        (a == 0) {\",\n                                    \"truncated\": false,\n                                    \"commentIds\": [\n                                        70\n                                    ]\n                                },\n                                {\n                                    \"source\": 105,\n                                    \"destination\": 109,\n                                    \"line\": \"            System.out.println(\\\"testing\\\");\",\n                                    \"truncated\": false,\n                                    \"commentIds\": [\n                                        68\n                                    ]\n                                },\n                                {\n                                    \"source\": 105,\n                                    \"destination\": 110,\n                                    \"line\": \"        }\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 105,\n                                    \"destination\": 111,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 106,\n                                    \"destination\": 112,\n                                    \"line\": \"        DefaultClientConfigImpl loadBalancerConfig = new DefaultClientConfigImpl();\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 107,\n                                    \"destination\": 113,\n                                    \"line\": \"        loadBalancerConfig.loadDefaultValues();\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 108,\n                                    \"destination\": 114,\n                                    \"line\": \"        loadBalancerConfig.setProperty(CommonClientConfigKey.MaxAutoRetriesNextServer, retryLimit);\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 109,\n                                    \"destination\": 115,\n                                    \"line\": \"        loadBalancerConfig.setProperty(CommonClientConfigKey.OkToRetryOnAllOperations, Boolean.TRUE);\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 110,\n                                    \"destination\": 116,\n                                    \"line\": \"        loadBalancerConfig.setProperty(CommonClientConfigKey.MaxConnectionsPerHost, aModule_MAX_CONNECTION);\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 111,\n                                    \"destination\": 117,\n                                    \"line\": \"        loadBalancerConfig.setProperty(CommonClientConfigKey.NFLoadBalancerPingClassName, DummyPing.class.getName());\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 112,\n                                    \"destination\": 118,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"ADDED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 113,\n                                    \"destination\": 119,\n                                    \"line\": \"        String ABC = \\\"asdf\\\";\",\n                                    \"truncated\": false,\n                                    \"commentIds\": [\n                                        73\n                                    ]\n                                },\n                                {\n                                    \"source\": 113,\n                                    \"destination\": 120,\n                                    \"line\": \"        System.out.println(ABC == \\\"asf\\\");\",\n                                    \"truncated\": false,\n                                    \"commentIds\": [\n                                        69\n                                    ]\n                                },\n                                {\n                                    \"source\": 113,\n                                    \"destination\": 121,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 113,\n                                    \"destination\": 122,\n                                    \"line\": \"        this.loadBalancer = new BaseLoadBalancer(loadBalancerConfig);\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 114,\n                                    \"destination\": 123,\n                                    \"line\": \"        List<Server> aModuleAddresses = addresses.stream().map(Server::new).collect(Collectors.toList());\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 115,\n                                    \"destination\": 124,\n                                    \"line\": \"        this.loadBalancer.addServers(aModuleAddresses);\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 116,\n                                    \"destination\": 125,\n                                    \"line\": \"        this.loadBalancerContext = new LoadBalancerContext(loadBalancer, loadBalancerConfig);\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 117,\n                                    \"destination\": 126,\n                                    \"line\": \"    }\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 118,\n                                    \"destination\": 127,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 119,\n                                    \"destination\": 128,\n                                    \"line\": \"    @Override\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 120,\n                                    \"destination\": 129,\n                                    \"line\": \"    @SuppressWarnings(\\\"unchecked\\\")\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 121,\n                                    \"destination\": 130,\n                                    \"line\": \"    public Mono<aModuleClientResponse> newHandler(BiFunction<? super aModuleClientResponse, ? super aModuleClientRequest, ? extends Publisher<Void>> biFunction) {\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 122,\n                                    \"destination\": 131,\n                                    \"line\": \"        return (Mono<aModuleClientResponse>) bridgeClient.newHandler((BiFunction<NettyInbound, NettyOutbound, Publisher<Void>>) biFunction);\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        }\n                    ],\n                    \"truncated\": false\n                }\n            ],\n            \"truncated\": false,\n            \"lineComments\": [\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 71,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Remove this unused \\\"B\\\" local variable. [[squid:S1481](http://10.177.92.24:9000/coding_rules#rule_key=squid:S1481)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686764,\n                    \"updatedDate\": 1542790686764,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 72,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'. [[squid:S00117](http://10.177.92.24:9000/coding_rules#rule_key=squid:S00117)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686785,\n                    \"updatedDate\": 1542790686785,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 70,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Change this condition so that it does not always evaluate to \\\"false\\\" [[squid:S2583](http://10.177.92.24:9000/coding_rules#rule_key=squid:S2583)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686749,\n                    \"updatedDate\": 1542790686749,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 68,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Replace this use of System.out or System.err by a logger. [[squid:S106](http://10.177.92.24:9000/coding_rules#rule_key=squid:S106)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686696,\n                    \"updatedDate\": 1542790686696,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 73,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'. [[squid:S00117](http://10.177.92.24:9000/coding_rules#rule_key=squid:S00117)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686806,\n                    \"updatedDate\": 1542790686806,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 69,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Replace this use of System.out or System.err by a logger. [[squid:S106](http://10.177.92.24:9000/coding_rules#rule_key=squid:S106)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686731,\n                    \"updatedDate\": 1542790686731,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                }\n            ]\n        },\n        {\n            \"source\": {\n                \"components\": [\n                    \"aModule-api-command-impl\",\n                    \"pom.xml\"\n                ],\n                \"parent\": \"aModule-api-command-impl\",\n                \"name\": \"pom.xml\",\n                \"extension\": \"xml\",\n                \"toString\": \"aModule-api-command-impl/pom.xml\"\n            },\n            \"destination\": {\n                \"components\": [\n                    \"aModule-api-command-impl\",\n                    \"pom.xml\"\n                ],\n                \"parent\": \"aModule-api-command-impl\",\n                \"name\": \"pom.xml\",\n                \"extension\": \"xml\",\n                \"toString\": \"aModule-api-command-impl/pom.xml\"\n            },\n            \"hunks\": [\n                {\n                    \"sourceLine\": 1,\n                    \"sourceSpan\": 16,\n                    \"destinationLine\": 1,\n                    \"destinationSpan\": 16,\n                    \"segments\": [\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 1,\n                                    \"destination\": 1,\n                                    \"line\": \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 2,\n                                    \"destination\": 2,\n                                    \"line\": \"<project xmlns=\\\"http://maven.apache.org/POM/4.0.0\\\" xmlns:xsi=\\\"http://www.w3.org/2001/XMLSchema-instance\\\" xsi:schemaLocation=\\\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\\\">\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 3,\n                                    \"destination\": 3,\n                                    \"line\": \"  <parent>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 4,\n                                    \"destination\": 4,\n                                    \"line\": \"    <groupId>com.gdn.package</groupId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 5,\n                                    \"destination\": 5,\n                                    \"line\": \"    <artifactId>aModule</artifactId>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"REMOVED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 6,\n                                    \"destination\": 6,\n                                    \"line\": \"    <version>0.0.1-4-SNAPSHOT</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"ADDED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 7,\n                                    \"destination\": 6,\n                                    \"line\": \"    <version>0.0.1-5-SNAPSHOT</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 7,\n                                    \"destination\": 7,\n                                    \"line\": \"  </parent>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 8,\n                                    \"destination\": 8,\n                                    \"line\": \"  <modelVersion>4.0.0</modelVersion>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 9,\n                                    \"destination\": 9,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 10,\n                                    \"destination\": 10,\n                                    \"line\": \"  <artifactId>aModule-api-command-impl</artifactId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 11,\n                                    \"destination\": 11,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 12,\n                                    \"destination\": 12,\n                                    \"line\": \"  <dependencies>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 13,\n                                    \"destination\": 13,\n                                    \"line\": \"    <dependency>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 14,\n                                    \"destination\": 14,\n                                    \"line\": \"      <groupId>com.gdn.package</groupId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 15,\n                                    \"destination\": 15,\n                                    \"line\": \"      <artifactId>aModule-api-command</artifactId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 16,\n                                    \"destination\": 16,\n                                    \"line\": \"      <version>${project.version}</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        }\n                    ],\n                    \"truncated\": false\n                }\n            ],\n            \"truncated\": false,\n            \"lineComments\": [\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 71,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Remove this unused \\\"B\\\" local variable. [[squid:S1481](http://10.177.92.24:9000/coding_rules#rule_key=squid:S1481)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686764,\n                    \"updatedDate\": 1542790686764,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 72,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'. [[squid:S00117](http://10.177.92.24:9000/coding_rules#rule_key=squid:S00117)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686785,\n                    \"updatedDate\": 1542790686785,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 70,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Change this condition so that it does not always evaluate to \\\"false\\\" [[squid:S2583](http://10.177.92.24:9000/coding_rules#rule_key=squid:S2583)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686749,\n                    \"updatedDate\": 1542790686749,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 68,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Replace this use of System.out or System.err by a logger. [[squid:S106](http://10.177.92.24:9000/coding_rules#rule_key=squid:S106)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686696,\n                    \"updatedDate\": 1542790686696,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 73,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'. [[squid:S00117](http://10.177.92.24:9000/coding_rules#rule_key=squid:S00117)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686806,\n                    \"updatedDate\": 1542790686806,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 69,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Replace this use of System.out or System.err by a logger. [[squid:S106](http://10.177.92.24:9000/coding_rules#rule_key=squid:S106)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686731,\n                    \"updatedDate\": 1542790686731,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                }\n            ]\n        },\n        {\n            \"source\": {\n                \"components\": [\n                    \"aModule-api-command-model\",\n                    \"pom.xml\"\n                ],\n                \"parent\": \"aModule-api-command-model\",\n                \"name\": \"pom.xml\",\n                \"extension\": \"xml\",\n                \"toString\": \"aModule-api-command-model/pom.xml\"\n            },\n            \"destination\": {\n                \"components\": [\n                    \"aModule-api-command-model\",\n                    \"pom.xml\"\n                ],\n                \"parent\": \"aModule-api-command-model\",\n                \"name\": \"pom.xml\",\n                \"extension\": \"xml\",\n                \"toString\": \"aModule-api-command-model/pom.xml\"\n            },\n            \"hunks\": [\n                {\n                    \"sourceLine\": 1,\n                    \"sourceSpan\": 16,\n                    \"destinationLine\": 1,\n                    \"destinationSpan\": 16,\n                    \"segments\": [\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 1,\n                                    \"destination\": 1,\n                                    \"line\": \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 2,\n                                    \"destination\": 2,\n                                    \"line\": \"<project xmlns=\\\"http://maven.apache.org/POM/4.0.0\\\" xmlns:xsi=\\\"http://www.w3.org/2001/XMLSchema-instance\\\" xsi:schemaLocation=\\\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\\\">\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 3,\n                                    \"destination\": 3,\n                                    \"line\": \"  <parent>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 4,\n                                    \"destination\": 4,\n                                    \"line\": \"    <groupId>com.gdn.package</groupId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 5,\n                                    \"destination\": 5,\n                                    \"line\": \"    <artifactId>aModule</artifactId>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"REMOVED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 6,\n                                    \"destination\": 6,\n                                    \"line\": \"    <version>0.0.1-4-SNAPSHOT</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"ADDED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 7,\n                                    \"destination\": 6,\n                                    \"line\": \"    <version>0.0.1-5-SNAPSHOT</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 7,\n                                    \"destination\": 7,\n                                    \"line\": \"  </parent>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 8,\n                                    \"destination\": 8,\n                                    \"line\": \"  <modelVersion>4.0.0</modelVersion>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 9,\n                                    \"destination\": 9,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 10,\n                                    \"destination\": 10,\n                                    \"line\": \"  <artifactId>aModule-api-command-model</artifactId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 11,\n                                    \"destination\": 11,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 12,\n                                    \"destination\": 12,\n                                    \"line\": \"  <dependencies>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 13,\n                                    \"destination\": 13,\n                                    \"line\": \"    <dependency>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 14,\n                                    \"destination\": 14,\n                                    \"line\": \"      <groupId>com.gdn.package</groupId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 15,\n                                    \"destination\": 15,\n                                    \"line\": \"      <artifactId>aModule-api-validation</artifactId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 16,\n                                    \"destination\": 16,\n                                    \"line\": \"      <version>${project.version}</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        }\n                    ],\n                    \"truncated\": false\n                },\n                {\n                    \"sourceLine\": 20,\n                    \"sourceSpan\": 11,\n                    \"destinationLine\": 20,\n                    \"destinationSpan\": 11,\n                    \"segments\": [\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 20,\n                                    \"destination\": 20,\n                                    \"line\": \"      <artifactId>aModule-api-web-model</artifactId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 21,\n                                    \"destination\": 21,\n                                    \"line\": \"      <version>${project.version}</version>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 22,\n                                    \"destination\": 22,\n                                    \"line\": \"    </dependency>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 23,\n                                    \"destination\": 23,\n                                    \"line\": \"    <dependency>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 24,\n                                    \"destination\": 24,\n                                    \"line\": \"      <groupId>com.gdn.package</groupId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 25,\n                                    \"destination\": 25,\n                                    \"line\": \"      <artifactId>aModule-api-client-model</artifactId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 26,\n                                    \"destination\": 26,\n                                    \"line\": \"      <version>${project.version}</version>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 27,\n                                    \"destination\": 27,\n                                    \"line\": \"    </dependency>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 28,\n                                    \"destination\": 28,\n                                    \"line\": \"  </dependencies>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 29,\n                                    \"destination\": 29,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"REMOVED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 30,\n                                    \"destination\": 30,\n                                    \"line\": \"</project>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"ADDED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 31,\n                                    \"destination\": 30,\n                                    \"line\": \"</project>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        }\n                    ],\n                    \"truncated\": false\n                }\n            ],\n            \"truncated\": false,\n            \"lineComments\": [\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 71,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Remove this unused \\\"B\\\" local variable. [[squid:S1481](http://10.177.92.24:9000/coding_rules#rule_key=squid:S1481)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686764,\n                    \"updatedDate\": 1542790686764,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 72,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'. [[squid:S00117](http://10.177.92.24:9000/coding_rules#rule_key=squid:S00117)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686785,\n                    \"updatedDate\": 1542790686785,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 70,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Change this condition so that it does not always evaluate to \\\"false\\\" [[squid:S2583](http://10.177.92.24:9000/coding_rules#rule_key=squid:S2583)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686749,\n                    \"updatedDate\": 1542790686749,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 68,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Replace this use of System.out or System.err by a logger. [[squid:S106](http://10.177.92.24:9000/coding_rules#rule_key=squid:S106)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686696,\n                    \"updatedDate\": 1542790686696,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 73,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'. [[squid:S00117](http://10.177.92.24:9000/coding_rules#rule_key=squid:S00117)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686806,\n                    \"updatedDate\": 1542790686806,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 69,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Replace this use of System.out or System.err by a logger. [[squid:S106](http://10.177.92.24:9000/coding_rules#rule_key=squid:S106)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686731,\n                    \"updatedDate\": 1542790686731,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                }\n            ]\n        },\n        {\n            \"source\": {\n                \"components\": [\n                    \"aModule-api-command\",\n                    \"pom.xml\"\n                ],\n                \"parent\": \"aModule-api-command\",\n                \"name\": \"pom.xml\",\n                \"extension\": \"xml\",\n                \"toString\": \"aModule-api-command/pom.xml\"\n            },\n            \"destination\": {\n                \"components\": [\n                    \"aModule-api-command\",\n                    \"pom.xml\"\n                ],\n                \"parent\": \"aModule-api-command\",\n                \"name\": \"pom.xml\",\n                \"extension\": \"xml\",\n                \"toString\": \"aModule-api-command/pom.xml\"\n            },\n            \"hunks\": [\n                {\n                    \"sourceLine\": 1,\n                    \"sourceSpan\": 16,\n                    \"destinationLine\": 1,\n                    \"destinationSpan\": 16,\n                    \"segments\": [\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 1,\n                                    \"destination\": 1,\n                                    \"line\": \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 2,\n                                    \"destination\": 2,\n                                    \"line\": \"<project xmlns=\\\"http://maven.apache.org/POM/4.0.0\\\" xmlns:xsi=\\\"http://www.w3.org/2001/XMLSchema-instance\\\" xsi:schemaLocation=\\\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\\\">\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 3,\n                                    \"destination\": 3,\n                                    \"line\": \"  <parent>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 4,\n                                    \"destination\": 4,\n                                    \"line\": \"    <groupId>com.gdn.package</groupId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 5,\n                                    \"destination\": 5,\n                                    \"line\": \"    <artifactId>aModule</artifactId>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"REMOVED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 6,\n                                    \"destination\": 6,\n                                    \"line\": \"    <version>0.0.1-4-SNAPSHOT</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"ADDED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 7,\n                                    \"destination\": 6,\n                                    \"line\": \"    <version>0.0.1-5-SNAPSHOT</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 7,\n                                    \"destination\": 7,\n                                    \"line\": \"  </parent>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 8,\n                                    \"destination\": 8,\n                                    \"line\": \"  <modelVersion>4.0.0</modelVersion>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 9,\n                                    \"destination\": 9,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 10,\n                                    \"destination\": 10,\n                                    \"line\": \"  <artifactId>aModule-api-command</artifactId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 11,\n                                    \"destination\": 11,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 12,\n                                    \"destination\": 12,\n                                    \"line\": \"  <dependencies>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 13,\n                                    \"destination\": 13,\n                                    \"line\": \"    <dependency>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 14,\n                                    \"destination\": 14,\n                                    \"line\": \"      <groupId>com.gdn.package</groupId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 15,\n                                    \"destination\": 15,\n                                    \"line\": \"      <artifactId>aModule-api-command-model</artifactId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 16,\n                                    \"destination\": 16,\n                                    \"line\": \"      <version>${project.version}</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        }\n                    ],\n                    \"truncated\": false\n                }\n            ],\n            \"truncated\": false,\n            \"lineComments\": [\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 71,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Remove this unused \\\"B\\\" local variable. [[squid:S1481](http://10.177.92.24:9000/coding_rules#rule_key=squid:S1481)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686764,\n                    \"updatedDate\": 1542790686764,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 72,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'. [[squid:S00117](http://10.177.92.24:9000/coding_rules#rule_key=squid:S00117)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686785,\n                    \"updatedDate\": 1542790686785,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 70,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Change this condition so that it does not always evaluate to \\\"false\\\" [[squid:S2583](http://10.177.92.24:9000/coding_rules#rule_key=squid:S2583)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686749,\n                    \"updatedDate\": 1542790686749,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 68,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Replace this use of System.out or System.err by a logger. [[squid:S106](http://10.177.92.24:9000/coding_rules#rule_key=squid:S106)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686696,\n                    \"updatedDate\": 1542790686696,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 73,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'. [[squid:S00117](http://10.177.92.24:9000/coding_rules#rule_key=squid:S00117)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686806,\n                    \"updatedDate\": 1542790686806,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 69,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Replace this use of System.out or System.err by a logger. [[squid:S106](http://10.177.92.24:9000/coding_rules#rule_key=squid:S106)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686731,\n                    \"updatedDate\": 1542790686731,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                }\n            ]\n        },\n        {\n            \"source\": {\n                \"components\": [\n                    \"aModule-api-entity\",\n                    \"pom.xml\"\n                ],\n                \"parent\": \"aModule-api-entity\",\n                \"name\": \"pom.xml\",\n                \"extension\": \"xml\",\n                \"toString\": \"aModule-api-entity/pom.xml\"\n            },\n            \"destination\": {\n                \"components\": [\n                    \"aModule-api-entity\",\n                    \"pom.xml\"\n                ],\n                \"parent\": \"aModule-api-entity\",\n                \"name\": \"pom.xml\",\n                \"extension\": \"xml\",\n                \"toString\": \"aModule-api-entity/pom.xml\"\n            },\n            \"hunks\": [\n                {\n                    \"sourceLine\": 1,\n                    \"sourceSpan\": 12,\n                    \"destinationLine\": 1,\n                    \"destinationSpan\": 12,\n                    \"segments\": [\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 1,\n                                    \"destination\": 1,\n                                    \"line\": \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 2,\n                                    \"destination\": 2,\n                                    \"line\": \"<project xmlns=\\\"http://maven.apache.org/POM/4.0.0\\\" xmlns:xsi=\\\"http://www.w3.org/2001/XMLSchema-instance\\\" xsi:schemaLocation=\\\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\\\">\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 3,\n                                    \"destination\": 3,\n                                    \"line\": \"  <parent>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 4,\n                                    \"destination\": 4,\n                                    \"line\": \"    <groupId>com.gdn.package</groupId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 5,\n                                    \"destination\": 5,\n                                    \"line\": \"    <artifactId>aModule</artifactId>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"REMOVED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 6,\n                                    \"destination\": 6,\n                                    \"line\": \"    <version>0.0.1-4-SNAPSHOT</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"ADDED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 7,\n                                    \"destination\": 6,\n                                    \"line\": \"    <version>0.0.1-5-SNAPSHOT</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 7,\n                                    \"destination\": 7,\n                                    \"line\": \"  </parent>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 8,\n                                    \"destination\": 8,\n                                    \"line\": \"  <modelVersion>4.0.0</modelVersion>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 9,\n                                    \"destination\": 9,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 10,\n                                    \"destination\": 10,\n                                    \"line\": \"  <artifactId>aModule-api-entity</artifactId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 11,\n                                    \"destination\": 11,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 12,\n                                    \"destination\": 12,\n                                    \"line\": \"</project>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        }\n                    ],\n                    \"truncated\": false\n                }\n            ],\n            \"truncated\": false,\n            \"lineComments\": [\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 71,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Remove this unused \\\"B\\\" local variable. [[squid:S1481](http://10.177.92.24:9000/coding_rules#rule_key=squid:S1481)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686764,\n                    \"updatedDate\": 1542790686764,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 72,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'. [[squid:S00117](http://10.177.92.24:9000/coding_rules#rule_key=squid:S00117)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686785,\n                    \"updatedDate\": 1542790686785,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 70,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Change this condition so that it does not always evaluate to \\\"false\\\" [[squid:S2583](http://10.177.92.24:9000/coding_rules#rule_key=squid:S2583)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686749,\n                    \"updatedDate\": 1542790686749,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 68,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Replace this use of System.out or System.err by a logger. [[squid:S106](http://10.177.92.24:9000/coding_rules#rule_key=squid:S106)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686696,\n                    \"updatedDate\": 1542790686696,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 73,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'. [[squid:S00117](http://10.177.92.24:9000/coding_rules#rule_key=squid:S00117)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686806,\n                    \"updatedDate\": 1542790686806,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 69,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Replace this use of System.out or System.err by a logger. [[squid:S106](http://10.177.92.24:9000/coding_rules#rule_key=squid:S106)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686731,\n                    \"updatedDate\": 1542790686731,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                }\n            ]\n        },\n        {\n            \"source\": {\n                \"components\": [\n                    \"aModule-api-properties\",\n                    \"pom.xml\"\n                ],\n                \"parent\": \"aModule-api-properties\",\n                \"name\": \"pom.xml\",\n                \"extension\": \"xml\",\n                \"toString\": \"aModule-api-properties/pom.xml\"\n            },\n            \"destination\": {\n                \"components\": [\n                    \"aModule-api-properties\",\n                    \"pom.xml\"\n                ],\n                \"parent\": \"aModule-api-properties\",\n                \"name\": \"pom.xml\",\n                \"extension\": \"xml\",\n                \"toString\": \"aModule-api-properties/pom.xml\"\n            },\n            \"hunks\": [\n                {\n                    \"sourceLine\": 1,\n                    \"sourceSpan\": 20,\n                    \"destinationLine\": 1,\n                    \"destinationSpan\": 20,\n                    \"segments\": [\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 1,\n                                    \"destination\": 1,\n                                    \"line\": \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 2,\n                                    \"destination\": 2,\n                                    \"line\": \"<project xmlns=\\\"http://maven.apache.org/POM/4.0.0\\\" xmlns:xsi=\\\"http://www.w3.org/2001/XMLSchema-instance\\\" xsi:schemaLocation=\\\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\\\">\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 3,\n                                    \"destination\": 3,\n                                    \"line\": \"  <parent>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 4,\n                                    \"destination\": 4,\n                                    \"line\": \"    <groupId>com.gdn.package</groupId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 5,\n                                    \"destination\": 5,\n                                    \"line\": \"    <artifactId>aModule</artifactId>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"REMOVED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 6,\n                                    \"destination\": 6,\n                                    \"line\": \"    <version>0.0.1-4-SNAPSHOT</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"ADDED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 7,\n                                    \"destination\": 6,\n                                    \"line\": \"    <version>0.0.1-5-SNAPSHOT</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 7,\n                                    \"destination\": 7,\n                                    \"line\": \"  </parent>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 8,\n                                    \"destination\": 8,\n                                    \"line\": \"  <modelVersion>4.0.0</modelVersion>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 9,\n                                    \"destination\": 9,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 10,\n                                    \"destination\": 10,\n                                    \"line\": \"  <artifactId>aModule-api-properties</artifactId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 11,\n                                    \"destination\": 11,\n                                    \"line\": \"    <dependencies>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 12,\n                                    \"destination\": 12,\n                                    \"line\": \"        <dependency>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 13,\n                                    \"destination\": 13,\n                                    \"line\": \"            <groupId>com.gdn.package</groupId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 14,\n                                    \"destination\": 14,\n                                    \"line\": \"            <artifactId>aModule-api-entity</artifactId>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"REMOVED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 15,\n                                    \"destination\": 15,\n                                    \"line\": \"            <version>0.0.1-4-SNAPSHOT</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"ADDED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 16,\n                                    \"destination\": 15,\n                                    \"line\": \"            <version>0.0.1-5-SNAPSHOT</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 16,\n                                    \"destination\": 16,\n                                    \"line\": \"            <scope>compile</scope>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 17,\n                                    \"destination\": 17,\n                                    \"line\": \"        </dependency>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 18,\n                                    \"destination\": 18,\n                                    \"line\": \"    </dependencies>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 19,\n                                    \"destination\": 19,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 20,\n                                    \"destination\": 20,\n                                    \"line\": \"</project>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        }\n                    ],\n                    \"truncated\": false\n                }\n            ],\n            \"truncated\": false,\n            \"lineComments\": [\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 71,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Remove this unused \\\"B\\\" local variable. [[squid:S1481](http://10.177.92.24:9000/coding_rules#rule_key=squid:S1481)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686764,\n                    \"updatedDate\": 1542790686764,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 72,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'. [[squid:S00117](http://10.177.92.24:9000/coding_rules#rule_key=squid:S00117)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686785,\n                    \"updatedDate\": 1542790686785,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 70,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Change this condition so that it does not always evaluate to \\\"false\\\" [[squid:S2583](http://10.177.92.24:9000/coding_rules#rule_key=squid:S2583)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686749,\n                    \"updatedDate\": 1542790686749,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 68,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Replace this use of System.out or System.err by a logger. [[squid:S106](http://10.177.92.24:9000/coding_rules#rule_key=squid:S106)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686696,\n                    \"updatedDate\": 1542790686696,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 73,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'. [[squid:S00117](http://10.177.92.24:9000/coding_rules#rule_key=squid:S00117)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686806,\n                    \"updatedDate\": 1542790686806,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 69,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Replace this use of System.out or System.err by a logger. [[squid:S106](http://10.177.92.24:9000/coding_rules#rule_key=squid:S106)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686731,\n                    \"updatedDate\": 1542790686731,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                }\n            ]\n        },\n        {\n            \"source\": {\n                \"components\": [\n                    \"aModule-api-repository\",\n                    \"pom.xml\"\n                ],\n                \"parent\": \"aModule-api-repository\",\n                \"name\": \"pom.xml\",\n                \"extension\": \"xml\",\n                \"toString\": \"aModule-api-repository/pom.xml\"\n            },\n            \"destination\": {\n                \"components\": [\n                    \"aModule-api-repository\",\n                    \"pom.xml\"\n                ],\n                \"parent\": \"aModule-api-repository\",\n                \"name\": \"pom.xml\",\n                \"extension\": \"xml\",\n                \"toString\": \"aModule-api-repository/pom.xml\"\n            },\n            \"hunks\": [\n                {\n                    \"sourceLine\": 1,\n                    \"sourceSpan\": 25,\n                    \"destinationLine\": 1,\n                    \"destinationSpan\": 25,\n                    \"segments\": [\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 1,\n                                    \"destination\": 1,\n                                    \"line\": \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 2,\n                                    \"destination\": 2,\n                                    \"line\": \"<project xmlns=\\\"http://maven.apache.org/POM/4.0.0\\\" xmlns:xsi=\\\"http://www.w3.org/2001/XMLSchema-instance\\\" xsi:schemaLocation=\\\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\\\">\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 3,\n                                    \"destination\": 3,\n                                    \"line\": \"  <parent>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 4,\n                                    \"destination\": 4,\n                                    \"line\": \"    <groupId>com.gdn.package</groupId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 5,\n                                    \"destination\": 5,\n                                    \"line\": \"    <artifactId>aModule</artifactId>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"REMOVED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 6,\n                                    \"destination\": 6,\n                                    \"line\": \"    <version>0.0.1-4-SNAPSHOT</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"ADDED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 7,\n                                    \"destination\": 6,\n                                    \"line\": \"    <version>0.0.1-5-SNAPSHOT</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 7,\n                                    \"destination\": 7,\n                                    \"line\": \"  </parent>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 8,\n                                    \"destination\": 8,\n                                    \"line\": \"  <modelVersion>4.0.0</modelVersion>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 9,\n                                    \"destination\": 9,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 10,\n                                    \"destination\": 10,\n                                    \"line\": \"  <artifactId>aModule-api-repository</artifactId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 11,\n                                    \"destination\": 11,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 12,\n                                    \"destination\": 12,\n                                    \"line\": \"  <dependencies>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 13,\n                                    \"destination\": 13,\n                                    \"line\": \"    <dependency>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 14,\n                                    \"destination\": 14,\n                                    \"line\": \"      <groupId>com.gdn.package</groupId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 15,\n                                    \"destination\": 15,\n                                    \"line\": \"      <artifactId>aModule-api-entity</artifactId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 16,\n                                    \"destination\": 16,\n                                    \"line\": \"      <version>${project.version}</version>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 17,\n                                    \"destination\": 17,\n                                    \"line\": \"    </dependency>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 18,\n                                    \"destination\": 18,\n                                    \"line\": \"    <dependency>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 19,\n                                    \"destination\": 19,\n                                    \"line\": \"      <groupId>de.flapdoodle.embed</groupId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 20,\n                                    \"destination\": 20,\n                                    \"line\": \"      <artifactId>de.flapdoodle.embed.mongo</artifactId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 21,\n                                    \"destination\": 21,\n                                    \"line\": \"      <scope>test</scope>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 22,\n                                    \"destination\": 22,\n                                    \"line\": \"    </dependency>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 23,\n                                    \"destination\": 23,\n                                    \"line\": \"  </dependencies>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 24,\n                                    \"destination\": 24,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"REMOVED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 25,\n                                    \"destination\": 25,\n                                    \"line\": \"</project>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"ADDED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 26,\n                                    \"destination\": 25,\n                                    \"line\": \"</project>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        }\n                    ],\n                    \"truncated\": false\n                }\n            ],\n            \"truncated\": false,\n            \"lineComments\": [\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 71,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Remove this unused \\\"B\\\" local variable. [[squid:S1481](http://10.177.92.24:9000/coding_rules#rule_key=squid:S1481)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686764,\n                    \"updatedDate\": 1542790686764,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 72,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'. [[squid:S00117](http://10.177.92.24:9000/coding_rules#rule_key=squid:S00117)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686785,\n                    \"updatedDate\": 1542790686785,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 70,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Change this condition so that it does not always evaluate to \\\"false\\\" [[squid:S2583](http://10.177.92.24:9000/coding_rules#rule_key=squid:S2583)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686749,\n                    \"updatedDate\": 1542790686749,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 68,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Replace this use of System.out or System.err by a logger. [[squid:S106](http://10.177.92.24:9000/coding_rules#rule_key=squid:S106)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686696,\n                    \"updatedDate\": 1542790686696,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 73,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'. [[squid:S00117](http://10.177.92.24:9000/coding_rules#rule_key=squid:S00117)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686806,\n                    \"updatedDate\": 1542790686806,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 69,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Replace this use of System.out or System.err by a logger. [[squid:S106](http://10.177.92.24:9000/coding_rules#rule_key=squid:S106)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686731,\n                    \"updatedDate\": 1542790686731,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                }\n            ]\n        },\n        {\n            \"source\": {\n                \"components\": [\n                    \"aModule-api-streaming-model\",\n                    \"pom.xml\"\n                ],\n                \"parent\": \"aModule-api-streaming-model\",\n                \"name\": \"pom.xml\",\n                \"extension\": \"xml\",\n                \"toString\": \"aModule-api-streaming-model/pom.xml\"\n            },\n            \"destination\": {\n                \"components\": [\n                    \"aModule-api-streaming-model\",\n                    \"pom.xml\"\n                ],\n                \"parent\": \"aModule-api-streaming-model\",\n                \"name\": \"pom.xml\",\n                \"extension\": \"xml\",\n                \"toString\": \"aModule-api-streaming-model/pom.xml\"\n            },\n            \"hunks\": [\n                {\n                    \"sourceLine\": 1,\n                    \"sourceSpan\": 12,\n                    \"destinationLine\": 1,\n                    \"destinationSpan\": 12,\n                    \"segments\": [\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 1,\n                                    \"destination\": 1,\n                                    \"line\": \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 2,\n                                    \"destination\": 2,\n                                    \"line\": \"<project xmlns=\\\"http://maven.apache.org/POM/4.0.0\\\" xmlns:xsi=\\\"http://www.w3.org/2001/XMLSchema-instance\\\" xsi:schemaLocation=\\\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\\\">\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 3,\n                                    \"destination\": 3,\n                                    \"line\": \"  <parent>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 4,\n                                    \"destination\": 4,\n                                    \"line\": \"    <groupId>com.gdn.package</groupId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 5,\n                                    \"destination\": 5,\n                                    \"line\": \"    <artifactId>aModule</artifactId>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"REMOVED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 6,\n                                    \"destination\": 6,\n                                    \"line\": \"    <version>0.0.1-4-SNAPSHOT</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"ADDED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 7,\n                                    \"destination\": 6,\n                                    \"line\": \"    <version>0.0.1-5-SNAPSHOT</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 7,\n                                    \"destination\": 7,\n                                    \"line\": \"  </parent>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 8,\n                                    \"destination\": 8,\n                                    \"line\": \"  <modelVersion>4.0.0</modelVersion>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 9,\n                                    \"destination\": 9,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 10,\n                                    \"destination\": 10,\n                                    \"line\": \"  <artifactId>aModule-api-streaming-model</artifactId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 11,\n                                    \"destination\": 11,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"REMOVED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 12,\n                                    \"destination\": 12,\n                                    \"line\": \"</project>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"ADDED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 13,\n                                    \"destination\": 12,\n                                    \"line\": \"</project>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        }\n                    ],\n                    \"truncated\": false\n                }\n            ],\n            \"truncated\": false,\n            \"lineComments\": [\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 71,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Remove this unused \\\"B\\\" local variable. [[squid:S1481](http://10.177.92.24:9000/coding_rules#rule_key=squid:S1481)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686764,\n                    \"updatedDate\": 1542790686764,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 72,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'. [[squid:S00117](http://10.177.92.24:9000/coding_rules#rule_key=squid:S00117)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686785,\n                    \"updatedDate\": 1542790686785,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 70,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Change this condition so that it does not always evaluate to \\\"false\\\" [[squid:S2583](http://10.177.92.24:9000/coding_rules#rule_key=squid:S2583)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686749,\n                    \"updatedDate\": 1542790686749,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 68,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Replace this use of System.out or System.err by a logger. [[squid:S106](http://10.177.92.24:9000/coding_rules#rule_key=squid:S106)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686696,\n                    \"updatedDate\": 1542790686696,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 73,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'. [[squid:S00117](http://10.177.92.24:9000/coding_rules#rule_key=squid:S00117)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686806,\n                    \"updatedDate\": 1542790686806,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 69,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Replace this use of System.out or System.err by a logger. [[squid:S106](http://10.177.92.24:9000/coding_rules#rule_key=squid:S106)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686731,\n                    \"updatedDate\": 1542790686731,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                }\n            ]\n        },\n        {\n            \"source\": {\n                \"components\": [\n                    \"aModule-api-streaming\",\n                    \"pom.xml\"\n                ],\n                \"parent\": \"aModule-api-streaming\",\n                \"name\": \"pom.xml\",\n                \"extension\": \"xml\",\n                \"toString\": \"aModule-api-streaming/pom.xml\"\n            },\n            \"destination\": {\n                \"components\": [\n                    \"aModule-api-streaming\",\n                    \"pom.xml\"\n                ],\n                \"parent\": \"aModule-api-streaming\",\n                \"name\": \"pom.xml\",\n                \"extension\": \"xml\",\n                \"toString\": \"aModule-api-streaming/pom.xml\"\n            },\n            \"hunks\": [\n                {\n                    \"sourceLine\": 1,\n                    \"sourceSpan\": 16,\n                    \"destinationLine\": 1,\n                    \"destinationSpan\": 16,\n                    \"segments\": [\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 1,\n                                    \"destination\": 1,\n                                    \"line\": \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 2,\n                                    \"destination\": 2,\n                                    \"line\": \"<project xmlns=\\\"http://maven.apache.org/POM/4.0.0\\\" xmlns:xsi=\\\"http://www.w3.org/2001/XMLSchema-instance\\\" xsi:schemaLocation=\\\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\\\">\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 3,\n                                    \"destination\": 3,\n                                    \"line\": \"  <parent>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 4,\n                                    \"destination\": 4,\n                                    \"line\": \"    <groupId>com.gdn.package</groupId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 5,\n                                    \"destination\": 5,\n                                    \"line\": \"    <artifactId>aModule</artifactId>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"REMOVED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 6,\n                                    \"destination\": 6,\n                                    \"line\": \"    <version>0.0.1-4-SNAPSHOT</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"ADDED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 7,\n                                    \"destination\": 6,\n                                    \"line\": \"    <version>0.0.1-5-SNAPSHOT</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 7,\n                                    \"destination\": 7,\n                                    \"line\": \"  </parent>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 8,\n                                    \"destination\": 8,\n                                    \"line\": \"  <modelVersion>4.0.0</modelVersion>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 9,\n                                    \"destination\": 9,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 10,\n                                    \"destination\": 10,\n                                    \"line\": \"  <artifactId>aModule-api-streaming</artifactId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 11,\n                                    \"destination\": 11,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 12,\n                                    \"destination\": 12,\n                                    \"line\": \"  <dependencies>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 13,\n                                    \"destination\": 13,\n                                    \"line\": \"    <dependency>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 14,\n                                    \"destination\": 14,\n                                    \"line\": \"      <groupId>com.gdn.package</groupId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 15,\n                                    \"destination\": 15,\n                                    \"line\": \"      <artifactId>aModule-api-streaming-model</artifactId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 16,\n                                    \"destination\": 16,\n                                    \"line\": \"      <version>${project.version}</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        }\n                    ],\n                    \"truncated\": false\n                }\n            ],\n            \"truncated\": false,\n            \"lineComments\": [\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 71,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Remove this unused \\\"B\\\" local variable. [[squid:S1481](http://10.177.92.24:9000/coding_rules#rule_key=squid:S1481)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686764,\n                    \"updatedDate\": 1542790686764,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 72,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'. [[squid:S00117](http://10.177.92.24:9000/coding_rules#rule_key=squid:S00117)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686785,\n                    \"updatedDate\": 1542790686785,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 70,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Change this condition so that it does not always evaluate to \\\"false\\\" [[squid:S2583](http://10.177.92.24:9000/coding_rules#rule_key=squid:S2583)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686749,\n                    \"updatedDate\": 1542790686749,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 68,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Replace this use of System.out or System.err by a logger. [[squid:S106](http://10.177.92.24:9000/coding_rules#rule_key=squid:S106)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686696,\n                    \"updatedDate\": 1542790686696,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 73,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'. [[squid:S00117](http://10.177.92.24:9000/coding_rules#rule_key=squid:S00117)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686806,\n                    \"updatedDate\": 1542790686806,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 69,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Replace this use of System.out or System.err by a logger. [[squid:S106](http://10.177.92.24:9000/coding_rules#rule_key=squid:S106)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686731,\n                    \"updatedDate\": 1542790686731,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                }\n            ]\n        },\n        {\n            \"source\": {\n                \"components\": [\n                    \"aModule-api-validation\",\n                    \"pom.xml\"\n                ],\n                \"parent\": \"aModule-api-validation\",\n                \"name\": \"pom.xml\",\n                \"extension\": \"xml\",\n                \"toString\": \"aModule-api-validation/pom.xml\"\n            },\n            \"destination\": {\n                \"components\": [\n                    \"aModule-api-validation\",\n                    \"pom.xml\"\n                ],\n                \"parent\": \"aModule-api-validation\",\n                \"name\": \"pom.xml\",\n                \"extension\": \"xml\",\n                \"toString\": \"aModule-api-validation/pom.xml\"\n            },\n            \"hunks\": [\n                {\n                    \"sourceLine\": 1,\n                    \"sourceSpan\": 16,\n                    \"destinationLine\": 1,\n                    \"destinationSpan\": 16,\n                    \"segments\": [\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 1,\n                                    \"destination\": 1,\n                                    \"line\": \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 2,\n                                    \"destination\": 2,\n                                    \"line\": \"<project xmlns=\\\"http://maven.apache.org/POM/4.0.0\\\" xmlns:xsi=\\\"http://www.w3.org/2001/XMLSchema-instance\\\" xsi:schemaLocation=\\\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\\\">\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 3,\n                                    \"destination\": 3,\n                                    \"line\": \"  <parent>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 4,\n                                    \"destination\": 4,\n                                    \"line\": \"    <groupId>com.gdn.package</groupId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 5,\n                                    \"destination\": 5,\n                                    \"line\": \"    <artifactId>aModule</artifactId>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"REMOVED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 6,\n                                    \"destination\": 6,\n                                    \"line\": \"    <version>0.0.1-4-SNAPSHOT</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"ADDED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 7,\n                                    \"destination\": 6,\n                                    \"line\": \"    <version>0.0.1-5-SNAPSHOT</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 7,\n                                    \"destination\": 7,\n                                    \"line\": \"  </parent>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 8,\n                                    \"destination\": 8,\n                                    \"line\": \"  <modelVersion>4.0.0</modelVersion>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 9,\n                                    \"destination\": 9,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 10,\n                                    \"destination\": 10,\n                                    \"line\": \"  <artifactId>aModule-api-validation</artifactId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 11,\n                                    \"destination\": 11,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 12,\n                                    \"destination\": 12,\n                                    \"line\": \"  <dependencies>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 13,\n                                    \"destination\": 13,\n                                    \"line\": \"    <dependency>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 14,\n                                    \"destination\": 14,\n                                    \"line\": \"      <groupId>com.gdn.package</groupId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 15,\n                                    \"destination\": 15,\n                                    \"line\": \"      <artifactId>aModule-api-repository</artifactId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 16,\n                                    \"destination\": 16,\n                                    \"line\": \"      <version>${project.version}</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        }\n                    ],\n                    \"truncated\": false\n                }\n            ],\n            \"truncated\": false,\n            \"lineComments\": [\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 71,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Remove this unused \\\"B\\\" local variable. [[squid:S1481](http://10.177.92.24:9000/coding_rules#rule_key=squid:S1481)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686764,\n                    \"updatedDate\": 1542790686764,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 72,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'. [[squid:S00117](http://10.177.92.24:9000/coding_rules#rule_key=squid:S00117)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686785,\n                    \"updatedDate\": 1542790686785,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 70,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Change this condition so that it does not always evaluate to \\\"false\\\" [[squid:S2583](http://10.177.92.24:9000/coding_rules#rule_key=squid:S2583)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686749,\n                    \"updatedDate\": 1542790686749,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 68,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Replace this use of System.out or System.err by a logger. [[squid:S106](http://10.177.92.24:9000/coding_rules#rule_key=squid:S106)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686696,\n                    \"updatedDate\": 1542790686696,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 73,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'. [[squid:S00117](http://10.177.92.24:9000/coding_rules#rule_key=squid:S00117)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686806,\n                    \"updatedDate\": 1542790686806,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 69,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Replace this use of System.out or System.err by a logger. [[squid:S106](http://10.177.92.24:9000/coding_rules#rule_key=squid:S106)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686731,\n                    \"updatedDate\": 1542790686731,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                }\n            ]\n        },\n        {\n            \"source\": {\n                \"components\": [\n                    \"aModule-api-web-model\",\n                    \"pom.xml\"\n                ],\n                \"parent\": \"aModule-api-web-model\",\n                \"name\": \"pom.xml\",\n                \"extension\": \"xml\",\n                \"toString\": \"aModule-api-web-model/pom.xml\"\n            },\n            \"destination\": {\n                \"components\": [\n                    \"aModule-api-web-model\",\n                    \"pom.xml\"\n                ],\n                \"parent\": \"aModule-api-web-model\",\n                \"name\": \"pom.xml\",\n                \"extension\": \"xml\",\n                \"toString\": \"aModule-api-web-model/pom.xml\"\n            },\n            \"hunks\": [\n                {\n                    \"sourceLine\": 1,\n                    \"sourceSpan\": 25,\n                    \"destinationLine\": 1,\n                    \"destinationSpan\": 25,\n                    \"segments\": [\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 1,\n                                    \"destination\": 1,\n                                    \"line\": \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 2,\n                                    \"destination\": 2,\n                                    \"line\": \"<project xmlns=\\\"http://maven.apache.org/POM/4.0.0\\\" xmlns:xsi=\\\"http://www.w3.org/2001/XMLSchema-instance\\\" xsi:schemaLocation=\\\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\\\">\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 3,\n                                    \"destination\": 3,\n                                    \"line\": \"  <parent>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 4,\n                                    \"destination\": 4,\n                                    \"line\": \"    <groupId>com.gdn.package</groupId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 5,\n                                    \"destination\": 5,\n                                    \"line\": \"    <artifactId>aModule</artifactId>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"REMOVED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 6,\n                                    \"destination\": 6,\n                                    \"line\": \"    <version>0.0.1-4-SNAPSHOT</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"ADDED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 7,\n                                    \"destination\": 6,\n                                    \"line\": \"    <version>0.0.1-5-SNAPSHOT</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 7,\n                                    \"destination\": 7,\n                                    \"line\": \"  </parent>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 8,\n                                    \"destination\": 8,\n                                    \"line\": \"  <modelVersion>4.0.0</modelVersion>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 9,\n                                    \"destination\": 9,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 10,\n                                    \"destination\": 10,\n                                    \"line\": \"  <artifactId>aModule-api-web-model</artifactId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 11,\n                                    \"destination\": 11,\n                                    \"line\": \"  <dependencies>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 12,\n                                    \"destination\": 12,\n                                    \"line\": \"    <dependency>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 13,\n                                    \"destination\": 13,\n                                    \"line\": \"      <groupId>com.gdn.package</groupId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 14,\n                                    \"destination\": 14,\n                                    \"line\": \"      <artifactId>aModule-api-entity</artifactId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 15,\n                                    \"destination\": 15,\n                                    \"line\": \"      <version>${project.version}</version>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 16,\n                                    \"destination\": 16,\n                                    \"line\": \"      <scope>compile</scope>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 17,\n                                    \"destination\": 17,\n                                    \"line\": \"    </dependency>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 18,\n                                    \"destination\": 18,\n                                    \"line\": \"    <dependency>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 19,\n                                    \"destination\": 19,\n                                    \"line\": \"      <groupId>com.gdn.package</groupId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 20,\n                                    \"destination\": 20,\n                                    \"line\": \"      <artifactId>aModule-api-validation</artifactId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 21,\n                                    \"destination\": 21,\n                                    \"line\": \"      <version>${project.version}</version>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 22,\n                                    \"destination\": 22,\n                                    \"line\": \"    </dependency>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 23,\n                                    \"destination\": 23,\n                                    \"line\": \"  </dependencies>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 24,\n                                    \"destination\": 24,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"REMOVED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 25,\n                                    \"destination\": 25,\n                                    \"line\": \"</project>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"ADDED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 26,\n                                    \"destination\": 25,\n                                    \"line\": \"</project>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        }\n                    ],\n                    \"truncated\": false\n                }\n            ],\n            \"truncated\": false,\n            \"lineComments\": [\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 71,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Remove this unused \\\"B\\\" local variable. [[squid:S1481](http://10.177.92.24:9000/coding_rules#rule_key=squid:S1481)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686764,\n                    \"updatedDate\": 1542790686764,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 72,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'. [[squid:S00117](http://10.177.92.24:9000/coding_rules#rule_key=squid:S00117)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686785,\n                    \"updatedDate\": 1542790686785,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 70,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Change this condition so that it does not always evaluate to \\\"false\\\" [[squid:S2583](http://10.177.92.24:9000/coding_rules#rule_key=squid:S2583)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686749,\n                    \"updatedDate\": 1542790686749,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 68,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Replace this use of System.out or System.err by a logger. [[squid:S106](http://10.177.92.24:9000/coding_rules#rule_key=squid:S106)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686696,\n                    \"updatedDate\": 1542790686696,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 73,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'. [[squid:S00117](http://10.177.92.24:9000/coding_rules#rule_key=squid:S00117)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686806,\n                    \"updatedDate\": 1542790686806,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 69,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Replace this use of System.out or System.err by a logger. [[squid:S106](http://10.177.92.24:9000/coding_rules#rule_key=squid:S106)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686731,\n                    \"updatedDate\": 1542790686731,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                }\n            ]\n        },\n        {\n            \"source\": {\n                \"components\": [\n                    \"aModule-api-web\",\n                    \"pom.xml\"\n                ],\n                \"parent\": \"aModule-api-web\",\n                \"name\": \"pom.xml\",\n                \"extension\": \"xml\",\n                \"toString\": \"aModule-api-web/pom.xml\"\n            },\n            \"destination\": {\n                \"components\": [\n                    \"aModule-api-web\",\n                    \"pom.xml\"\n                ],\n                \"parent\": \"aModule-api-web\",\n                \"name\": \"pom.xml\",\n                \"extension\": \"xml\",\n                \"toString\": \"aModule-api-web/pom.xml\"\n            },\n            \"hunks\": [\n                {\n                    \"sourceLine\": 1,\n                    \"sourceSpan\": 16,\n                    \"destinationLine\": 1,\n                    \"destinationSpan\": 16,\n                    \"segments\": [\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 1,\n                                    \"destination\": 1,\n                                    \"line\": \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 2,\n                                    \"destination\": 2,\n                                    \"line\": \"<project xmlns=\\\"http://maven.apache.org/POM/4.0.0\\\" xmlns:xsi=\\\"http://www.w3.org/2001/XMLSchema-instance\\\" xsi:schemaLocation=\\\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\\\">\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 3,\n                                    \"destination\": 3,\n                                    \"line\": \"  <parent>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 4,\n                                    \"destination\": 4,\n                                    \"line\": \"    <groupId>com.gdn.package</groupId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 5,\n                                    \"destination\": 5,\n                                    \"line\": \"    <artifactId>aModule</artifactId>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"REMOVED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 6,\n                                    \"destination\": 6,\n                                    \"line\": \"    <version>0.0.1-4-SNAPSHOT</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"ADDED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 7,\n                                    \"destination\": 6,\n                                    \"line\": \"    <version>0.0.1-5-SNAPSHOT</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 7,\n                                    \"destination\": 7,\n                                    \"line\": \"  </parent>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 8,\n                                    \"destination\": 8,\n                                    \"line\": \"  <modelVersion>4.0.0</modelVersion>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 9,\n                                    \"destination\": 9,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 10,\n                                    \"destination\": 10,\n                                    \"line\": \"  <artifactId>aModule-api-web</artifactId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 11,\n                                    \"destination\": 11,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 12,\n                                    \"destination\": 12,\n                                    \"line\": \"  <build>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 13,\n                                    \"destination\": 13,\n                                    \"line\": \"    <plugins>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 14,\n                                    \"destination\": 14,\n                                    \"line\": \"      <plugin>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 15,\n                                    \"destination\": 15,\n                                    \"line\": \"        <groupId>org.springframework.cloud</groupId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 16,\n                                    \"destination\": 16,\n                                    \"line\": \"        <artifactId>spring-cloud-contract-maven-plugin</artifactId>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        }\n                    ],\n                    \"truncated\": false\n                }\n            ],\n            \"truncated\": false,\n            \"lineComments\": [\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 71,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Remove this unused \\\"B\\\" local variable. [[squid:S1481](http://10.177.92.24:9000/coding_rules#rule_key=squid:S1481)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686764,\n                    \"updatedDate\": 1542790686764,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 72,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'. [[squid:S00117](http://10.177.92.24:9000/coding_rules#rule_key=squid:S00117)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686785,\n                    \"updatedDate\": 1542790686785,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 70,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Change this condition so that it does not always evaluate to \\\"false\\\" [[squid:S2583](http://10.177.92.24:9000/coding_rules#rule_key=squid:S2583)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686749,\n                    \"updatedDate\": 1542790686749,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 68,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Replace this use of System.out or System.err by a logger. [[squid:S106](http://10.177.92.24:9000/coding_rules#rule_key=squid:S106)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686696,\n                    \"updatedDate\": 1542790686696,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 73,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'. [[squid:S00117](http://10.177.92.24:9000/coding_rules#rule_key=squid:S00117)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686806,\n                    \"updatedDate\": 1542790686806,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 69,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Replace this use of System.out or System.err by a logger. [[squid:S106](http://10.177.92.24:9000/coding_rules#rule_key=squid:S106)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686731,\n                    \"updatedDate\": 1542790686731,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                }\n            ]\n        },\n        {\n            \"source\": {\n                \"components\": [\n                    \"pom.xml\"\n                ],\n                \"parent\": \"\",\n                \"name\": \"pom.xml\",\n                \"extension\": \"xml\",\n                \"toString\": \"pom.xml\"\n            },\n            \"destination\": {\n                \"components\": [\n                    \"pom.xml\"\n                ],\n                \"parent\": \"\",\n                \"name\": \"pom.xml\",\n                \"extension\": \"xml\",\n                \"toString\": \"pom.xml\"\n            },\n            \"hunks\": [\n                {\n                    \"sourceLine\": 1,\n                    \"sourceSpan\": 17,\n                    \"destinationLine\": 1,\n                    \"destinationSpan\": 17,\n                    \"segments\": [\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 1,\n                                    \"destination\": 1,\n                                    \"line\": \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 2,\n                                    \"destination\": 2,\n                                    \"line\": \"<project xmlns=\\\"http://maven.apache.org/POM/4.0.0\\\" xmlns:xsi=\\\"http://www.w3.org/2001/XMLSchema-instance\\\" xsi:schemaLocation=\\\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\\\">\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 3,\n                                    \"destination\": 3,\n                                    \"line\": \"  <modelVersion>4.0.0</modelVersion>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 4,\n                                    \"destination\": 4,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 5,\n                                    \"destination\": 5,\n                                    \"line\": \"  <groupId>com.gdn.package</groupId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 6,\n                                    \"destination\": 6,\n                                    \"line\": \"  <artifactId>aModule</artifactId>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"REMOVED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 7,\n                                    \"destination\": 7,\n                                    \"line\": \"  <version>0.0.1-4-SNAPSHOT</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"ADDED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 8,\n                                    \"destination\": 7,\n                                    \"line\": \"  <version>0.0.1-5-SNAPSHOT</version>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 8,\n                                    \"destination\": 8,\n                                    \"line\": \"  <modules>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 9,\n                                    \"destination\": 9,\n                                    \"line\": \"    <module>aModule-api-entity</module>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 10,\n                                    \"destination\": 10,\n                                    \"line\": \"    <module>aModule-api-repository</module>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 11,\n                                    \"destination\": 11,\n                                    \"line\": \"    <module>aModule-api-app</module>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 12,\n                                    \"destination\": 12,\n                                    \"line\": \"    <module>aModule-api-command</module>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 13,\n                                    \"destination\": 13,\n                                    \"line\": \"    <module>aModule-api-command-impl</module>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 14,\n                                    \"destination\": 14,\n                                    \"line\": \"    <module>aModule-api-web</module>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 15,\n                                    \"destination\": 15,\n                                    \"line\": \"    <module>aModule-api-streaming</module>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 16,\n                                    \"destination\": 16,\n                                    \"line\": \"    <module>aModule-api-web-model</module>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 17,\n                                    \"destination\": 17,\n                                    \"line\": \"    <module>aModule-api-command-model</module>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        }\n                    ],\n                    \"truncated\": false\n                },\n                {\n                    \"sourceLine\": 59,\n                    \"sourceSpan\": 20,\n                    \"destinationLine\": 59,\n                    \"destinationSpan\": 27,\n                    \"segments\": [\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 59,\n                                    \"destination\": 59,\n                                    \"line\": \"    <!-- Sonar Exclude Modules -->\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 60,\n                                    \"destination\": 60,\n                                    \"line\": \"    <sonar.coverage.exclusions>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 61,\n                                    \"destination\": 61,\n                                    \"line\": \"      src/main/java/com/gdn/package/aModule/entity/**/*,\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 62,\n                                    \"destination\": 62,\n                                    \"line\": \"      src/main/java/com/gdn/package/aModule/properties/**/*,\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 63,\n                                    \"destination\": 63,\n                                    \"line\": \"      src/main/java/com/gdn/package/aModule/client/model/**/*,\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 64,\n                                    \"destination\": 64,\n                                    \"line\": \"      src/main/java/com/gdn/package/aModule/configurations/**/*,\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 65,\n                                    \"destination\": 65,\n                                    \"line\": \"      src/main/java/com/gdn/package/aModule/command/model/**/*\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 66,\n                                    \"destination\": 66,\n                                    \"line\": \"      src/main/java/com/gdn/package/aModule/streaming/model/**/*,\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 67,\n                                    \"destination\": 67,\n                                    \"line\": \"      src/main/java/com/gdn/package/aModule/web/model/**/*\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 68,\n                                    \"destination\": 68,\n                                    \"line\": \"    </sonar.coverage.exclusions>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"ADDED\",\n                            \"lines\": [\n                                {\n                                    \"source\": 69,\n                                    \"destination\": 69,\n                                    \"line\": \"    <sonar.jdbc.url>jdbc:h2:tcp://10.177.92.24:9092/sonar</sonar.jdbc.url>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 69,\n                                    \"destination\": 70,\n                                    \"line\": \"    <sonar.jdbc.username>sonar</sonar.jdbc.username>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 69,\n                                    \"destination\": 71,\n                                    \"line\": \"    <sonar.jdbc.password>sonar</sonar.jdbc.password>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 69,\n                                    \"destination\": 72,\n                                    \"line\": \"    <sonar.jdbc.driverClassName>org.h2.Driver</sonar.jdbc.driverClassName>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 69,\n                                    \"destination\": 73,\n                                    \"line\": \"    <sonar.host.url>http://10.177.92.24:9000</sonar.host.url>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 69,\n                                    \"destination\": 74,\n                                    \"line\": \"    <sonar.login>admin</sonar.login>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 69,\n                                    \"destination\": 75,\n                                    \"line\": \"    <sonar.password>admin</sonar.password>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        },\n                        {\n                            \"type\": \"CONTEXT\",\n                            \"lines\": [\n                                {\n                                    \"source\": 69,\n                                    \"destination\": 76,\n                                    \"line\": \"  </properties>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 70,\n                                    \"destination\": 77,\n                                    \"line\": \"\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 71,\n                                    \"destination\": 78,\n                                    \"line\": \"  <dependencyManagement>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 72,\n                                    \"destination\": 79,\n                                    \"line\": \"    <dependencies>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 73,\n                                    \"destination\": 80,\n                                    \"line\": \"      <dependency>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 74,\n                                    \"destination\": 81,\n                                    \"line\": \"        <groupId>org.springframework.cloud</groupId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 75,\n                                    \"destination\": 82,\n                                    \"line\": \"        <artifactId>spring-cloud-dependencies</artifactId>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 76,\n                                    \"destination\": 83,\n                                    \"line\": \"        <version>${spring-cloud.version}</version>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 77,\n                                    \"destination\": 84,\n                                    \"line\": \"        <type>pom</type>\",\n                                    \"truncated\": false\n                                },\n                                {\n                                    \"source\": 78,\n                                    \"destination\": 85,\n                                    \"line\": \"        <scope>import</scope>\",\n                                    \"truncated\": false\n                                }\n                            ],\n                            \"truncated\": false\n                        }\n                    ],\n                    \"truncated\": false\n                }\n            ],\n            \"truncated\": false,\n            \"lineComments\": [\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 71,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Remove this unused \\\"B\\\" local variable. [[squid:S1481](http://10.177.92.24:9000/coding_rules#rule_key=squid:S1481)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686764,\n                    \"updatedDate\": 1542790686764,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 72,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'. [[squid:S00117](http://10.177.92.24:9000/coding_rules#rule_key=squid:S00117)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686785,\n                    \"updatedDate\": 1542790686785,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 70,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Change this condition so that it does not always evaluate to \\\"false\\\" [[squid:S2583](http://10.177.92.24:9000/coding_rules#rule_key=squid:S2583)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686749,\n                    \"updatedDate\": 1542790686749,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 68,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Replace this use of System.out or System.err by a logger. [[squid:S106](http://10.177.92.24:9000/coding_rules#rule_key=squid:S106)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686696,\n                    \"updatedDate\": 1542790686696,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 73,\n                    \"version\": 0,\n                    \"text\": \"*MINOR* - Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'. [[squid:S00117](http://10.177.92.24:9000/coding_rules#rule_key=squid:S00117)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686806,\n                    \"updatedDate\": 1542790686806,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                },\n                {\n                    \"properties\": {\n                        \"repositoryId\": 1\n                    },\n                    \"id\": 69,\n                    \"version\": 0,\n                    \"text\": \"*MAJOR* - Replace this use of System.out or System.err by a logger. [[squid:S106](http://10.177.92.24:9000/coding_rules#rule_key=squid:S106)]\",\n                    \"author\": {\n                        \"name\": \"some.user\",\n                        \"emailAddress\": \"some.user@example.org\",\n                        \"id\": 1,\n                        \"displayName\": \"Some Random User\",\n                        \"active\": true,\n                        \"slug\": \"some.user\",\n                        \"type\": \"NORMAL\"\n                    },\n                    \"createdDate\": 1542790686731,\n                    \"updatedDate\": 1542790686731,\n                    \"comments\": [],\n                    \"tasks\": [],\n                    \"permittedOperations\": {\n                        \"editable\": true,\n                        \"deletable\": true\n                    }\n                }\n            ]\n        }\n    ],\n    \"truncated\": false\n}\n"
  },
  {
    "path": "src/test/resources/foo/module1/src/main/java/Foo.java",
    "content": "public class Foo {\n    public static void main(String[] args) {\n        System.out.println(\"Foo\");\n    }\n}"
  },
  {
    "path": "src/test/resources/foo/module2/src/main/java/Bar.java",
    "content": "public class Bar {\n    public static void main(String[] args) {\n        System.out.println(\"Bar\");\n    }\n}"
  },
  {
    "path": "src/test/resources/foo/sonar-project.properties",
    "content": "sonar.modules=module1,module2\nmodule1.sonar.sources=src/main/java\nmodule2.sonar.sources=src/main/java"
  }
]