public SonarResource apply(org.sonar.wsclient.services.Resource input) {

    io.gmind7.devops.ldap.sonar.resource.SonarResource output =
        new io.gmind7.devops.ldap.sonar.resource.SonarResource();

    output.setId(String.valueOf(input.getId()));
    output.setKey(StringUtils.defaultIfBlank(input.getKey(), ""));
    output.setName(StringUtils.defaultIfBlank(input.getName(), ""));
    output.setLongName(StringUtils.defaultIfBlank(input.getLongName(), ""));
    output.setScope(StringUtils.defaultIfBlank(input.getScope(), ""));
    output.setQualifier(StringUtils.defaultIfBlank(input.getQualifier(), ""));
    output.setLanguage(StringUtils.defaultIfBlank(input.getLanguage(), ""));
    output.setVersion(StringUtils.defaultIfBlank(input.getVersion(), ""));
    output.setCopy(StringUtils.defaultIfBlank(String.valueOf(input.getCopy()), ""));
    output.setDescription(StringUtils.defaultIfBlank(input.getDescription(), ""));
    output.setDate(input.getDate());

    List<org.sonar.wsclient.services.Measure> sonarMeasures = input.getMeasures();

    if (sonarMeasures != null) {
      List<io.gmind7.devops.ldap.sonar.measure.SonarMeasure> measures = Lists.newArrayList();
      for (org.sonar.wsclient.services.Measure sonarMeasure : sonarMeasures) {
        measures.add(sonarMeasureMapper.apply(input, sonarMeasure));
      }
      output.setMeasures(measures);
    } else {
      output.setMeasures(
          Lists.newArrayList(new io.gmind7.devops.ldap.sonar.measure.SonarMeasure()));
    }

    return output;
  }
  /** SONAR-6787 */
  @Test
  public void ensure_differential_period_4_and_5_defined_at_project_level_is_taken_into_account()
      throws Exception {
    orchestrator.getServer().provisionProject(PROJECT_KEY, PROJECT_KEY);
    setServerProperty(orchestrator, PROJECT_KEY, "sonar.timemachine.period4", "30");
    setServerProperty(orchestrator, PROJECT_KEY, "sonar.timemachine.period5", "previous_analysis");

    // Execute an analysis in the past to have a past snapshot without any issues
    orchestrator.getServer().associateProjectToQualityProfile(PROJECT_KEY, "xoo", "empty");
    orchestrator.executeBuild(
        SonarRunner.create(projectDir("shared/xoo-sample"))
            .setProperty("sonar.projectDate", formatDate(addDays(new Date(), -60))));

    // Second analysis -> issues will be created
    orchestrator
        .getServer()
        .restoreProfile(FileLocation.ofClasspath("/measureHistory/one-issue-per-line-profile.xml"));
    orchestrator
        .getServer()
        .associateProjectToQualityProfile(PROJECT_KEY, "xoo", "one-issue-per-line");
    orchestrator.executeBuild(SonarRunner.create(projectDir("shared/xoo-sample")));

    // New technical debt only comes from new issues
    Resource newTechnicalDebt =
        orchestrator
            .getServer()
            .getWsClient()
            .find(
                ResourceQuery.createForMetrics(
                        "sample:src/main/xoo/sample/Sample.xoo", "new_technical_debt")
                    .setIncludeTrends(true));
    List<Measure> measures = newTechnicalDebt.getMeasures();
    assertThat(measures.get(0).getVariation4()).isEqualTo(17);
    assertThat(measures.get(0).getVariation5()).isEqualTo(17);

    // Third analysis, with exactly the same profile -> no new issues so no new technical debt
    orchestrator
        .getServer()
        .associateProjectToQualityProfile(PROJECT_KEY, "xoo", "one-issue-per-line");
    orchestrator.executeBuild(SonarRunner.create(projectDir("shared/xoo-sample")));

    newTechnicalDebt =
        orchestrator
            .getServer()
            .getWsClient()
            .find(
                ResourceQuery.createForMetrics(
                        "sample:src/main/xoo/sample/Sample.xoo", "new_technical_debt")
                    .setIncludeTrends(true));

    // No variation => measure is purged
    assertThat(newTechnicalDebt).isNull();
  }
  /** SONAR-7093 */
  @Test
  public void ensure_leak_period_defined_at_project_level_is_taken_into_account() throws Exception {
    orchestrator.getServer().provisionProject(PROJECT_KEY, PROJECT_KEY);

    // Set a global property and a project property to ensure project property is used
    setServerProperty(orchestrator, "sonar.timemachine.period1", "previous_analysis");
    setServerProperty(orchestrator, PROJECT_KEY, "sonar.timemachine.period1", "30");

    // Execute an analysis in the past to have a past snapshot without any issues
    orchestrator.getServer().associateProjectToQualityProfile(PROJECT_KEY, "xoo", "empty");
    orchestrator.executeBuild(
        SonarRunner.create(projectDir("shared/xoo-sample"))
            .setProperty("sonar.projectDate", formatDate(addDays(new Date(), -15))));

    // Second analysis -> issues will be created
    orchestrator
        .getServer()
        .restoreProfile(FileLocation.ofClasspath("/measureHistory/one-issue-per-line-profile.xml"));
    orchestrator
        .getServer()
        .associateProjectToQualityProfile(PROJECT_KEY, "xoo", "one-issue-per-line");
    orchestrator.executeBuild(SonarRunner.create(projectDir("shared/xoo-sample")));

    // Third analysis -> There's no new issue from previous analysis
    orchestrator.executeBuild(SonarRunner.create(projectDir("shared/xoo-sample")));

    // Project should have 17 new issues for period 1
    Resource newTechnicalDebt =
        orchestrator
            .getServer()
            .getWsClient()
            .find(ResourceQuery.createForMetrics(PROJECT_KEY, "violations").setIncludeTrends(true));
    List<Measure> measures = newTechnicalDebt.getMeasures();
    assertThat(measures.get(0).getVariation1()).isEqualTo(17);

    // Check on ui that it's possible to define leak period on project
    new SeleneseTest(
            Selenese.builder()
                .setHtmlTestsInClasspath(
                    "define-leak-period-on-project",
                    "/measureHistory/DifferentialPeriodsTest/define-leak-period-on-project.html")
                .build())
        .runOn(orchestrator);
  }