public void mergeExistingOpenIssue(DefaultIssue raw, DefaultIssue base) {
    Preconditions.checkArgument(raw.isFromExternalRuleEngine() != (raw.type() == null), "At this stage issue type should be set for and only for external issues");
    Rule rule = ruleRepository.getByKey(raw.ruleKey());
    raw.setKey(base.key());
    raw.setNew(false);
    if (base.isChanged()) {
      // In case issue was moved from module or folder to the root project
      raw.setChanged(true);
    }
    setType(raw, rule);
    setCleanCodeAttribute(raw, rule);
    copyFields(raw, base);
    base.changes().forEach(raw::addChange);

    if (base.manualSeverity()) {
      raw.setManualSeverity(true);
      raw.setSeverity(base.severity());
    } else {
      updater.setPastSeverity(raw, base.severity(), changeContext);
    }
    // set component/module related fields from base in case current component has been moved
    // (in which case base issue belongs to original file and raw issue to component)
    raw.setComponentUuid(base.componentUuid());
    raw.setComponentKey(base.componentKey());

    // fields coming from raw
    updater.setPastLine(raw, base.getLine());
    updater.setPastLocations(raw, base.getLocations());
    updater.setRuleDescriptionContextKey(raw, base.getRuleDescriptionContextKey().orElse(null));
    updater.setPastMessage(raw, base.getMessage(), base.getMessageFormattings(), changeContext);
    updater.setPastGap(raw, base.gap(), changeContext);
    updater.setPastEffort(raw, base.effort(), changeContext);
    updater.setCodeVariants(raw, requireNonNull(base.codeVariants()), changeContext);
    updater.setImpacts(raw, base.impacts(), changeContext);
    updater.setCleanCodeAttribute(raw, base.getCleanCodeAttribute(), changeContext);
    updater.setPrioritizedRule(raw, base.isPrioritizedRule(), changeContext);
  }
@Test
  public void mergeExistingOpenIssue() {
    DefaultIssue raw = new DefaultIssue()
      .setNew(true)
      .setKey("RAW_KEY")
      .setRuleKey(XOO_X1)
      .setRuleDescriptionContextKey("spring")
      .setCleanCodeAttribute(CleanCodeAttribute.IDENTIFIABLE)
      .setCodeVariants(Set.of("foo", "bar"))
      .addImpact(SoftwareQuality.MAINTAINABILITY, Severity.HIGH)
      .setCreationDate(parseDate("2015-10-01"))
      .setUpdateDate(parseDate("2015-10-02"))
      .setCloseDate(parseDate("2015-10-03"));

    DbIssues.Locations issueLocations = DbIssues.Locations.newBuilder()
      .setTextRange(DbCommons.TextRange.newBuilder()
        .setStartLine(10)
        .setEndLine(12)
        .build())
      .build();

    DbIssues.MessageFormattings messageFormattings = DbIssues.MessageFormattings.newBuilder()
      .addMessageFormatting(DbIssues.MessageFormatting
        .newBuilder()
        .setStart(13)
        .setEnd(17)
        .setType(DbIssues.MessageFormattingType.CODE)
        .build())
      .build();

    DefaultIssue base = new DefaultIssue()
      .setKey("BASE_KEY")
      .setCreationDate(parseDate("2015-01-01"))
      .setUpdateDate(parseDate("2015-01-02"))
      .setCleanCodeAttribute(CleanCodeAttribute.FOCUSED)
      .setResolution(RESOLUTION_FALSE_POSITIVE)
      .setStatus(STATUS_RESOLVED)
      .setSeverity(BLOCKER)
      .setAssigneeUuid("base assignee uuid")
      .setAssigneeLogin("base assignee login")
      .setAuthorLogin("base author")
      .setTags(newArrayList("base tag"))
      .setOnDisabledRule(true)
      .setSelectedAt(1000L)
      .setLine(10)
      .setMessage("message with code")
      .setMessageFormattings(messageFormattings)
      .setGap(15d)
      .setRuleDescriptionContextKey("hibernate")
      .setCodeVariants(Set.of("donut"))
      .addImpact(SoftwareQuality.RELIABILITY, Severity.LOW)
      .setEffort(Duration.create(15L))
      .setManualSeverity(false)
      .setLocations(issueLocations)
      .addChange(new FieldDiffs().setDiff("foo", "bar", "donut"))
      .addChange(new FieldDiffs().setDiff("file", "A", "B"));

    when(debtCalculator.calculate(raw)).thenReturn(DEFAULT_DURATION);

    underTest.mergeExistingOpenIssue(raw, base);

    assertThat(raw.isNew()).isFalse();
    assertThat(raw.key()).isEqualTo("BASE_KEY");
    assertThat(raw.creationDate()).isEqualTo(base.creationDate());
    assertThat(raw.updateDate()).isEqualTo(base.updateDate());
    assertThat(raw.resolution()).isEqualTo(RESOLUTION_FALSE_POSITIVE);
    assertThat(raw.status()).isEqualTo(STATUS_RESOLVED);
    assertThat(raw.assignee()).isEqualTo("base assignee uuid");
    assertThat(raw.assigneeLogin()).isEqualTo("base assignee login");
    assertThat(raw.authorLogin()).isEqualTo("base author");
    assertThat(raw.tags()).containsOnly("base tag");
    assertThat(raw.codeVariants()).containsOnly("foo", "bar");
    assertThat(raw.effort()).isEqualTo(DEFAULT_DURATION);
    assertThat(raw.isOnDisabledRule()).isTrue();
    assertThat(raw.selectedAt()).isEqualTo(1000L);
    assertThat(raw.isChanged()).isFalse();
    assertThat(raw.changes()).hasSize(2);
    assertThat(raw.changes().get(0).diffs())
      .containsOnly(entry("foo", new FieldDiffs.Diff<>("bar", "donut")));
    assertThat(raw.changes().get(1).diffs())
      .containsOnly(entry("file", new FieldDiffs.Diff<>("A", "B")));
    assertThat(raw.impacts())
      .containsEntry(SoftwareQuality.MAINTAINABILITY, Severity.HIGH);
    verify(updater).setPastSeverity(raw, BLOCKER, issueChangeContext);
    verify(updater).setPastLine(raw, 10);
    verify(updater).setRuleDescriptionContextKey(raw, "hibernate");
    verify(updater).setCodeVariants(raw, Set.of("donut"), issueChangeContext);
    verify(updater).setPastMessage(raw, "message with code", messageFormattings, issueChangeContext);
    verify(updater).setPastEffort(raw, Duration.create(15L), issueChangeContext);
    verify(updater).setPastLocations(raw, issueLocations);
    verify(updater).setCleanCodeAttribute(raw, CleanCodeAttribute.FOCUSED, issueChangeContext);
  }