private static void addChangeset(Builder scmBuilder, BlameLine line) {
    BatchReport.Changesets.Changeset.Builder changesetBuilder =
        BatchReport.Changesets.Changeset.newBuilder();
    changesetBuilder.setRevision(line.revision());
    changesetBuilder.setDate(line.date().getTime());
    if (StringUtils.isNotBlank(line.author())) {
      changesetBuilder.setAuthor(normalizeString(line.author()));
    }

    scmBuilder.addChangeset(changesetBuilder.build());
  }
 private static void validateLine(BlameLine line, int lineId, InputFile file) {
   Preconditions.checkArgument(
       StringUtils.isNotBlank(line.revision()),
       "Blame revision is blank for file %s at line %s",
       file.relativePath(),
       lineId);
   Preconditions.checkArgument(
       line.date() != null,
       "Blame date is null for file %s at line %s",
       file.relativePath(),
       lineId);
 }
  @Override
  public synchronized void blameResult(InputFile file, List<BlameLine> lines) {
    Preconditions.checkNotNull(file);
    Preconditions.checkNotNull(lines);
    Preconditions.checkArgument(
        allFilesToBlame.contains(file),
        "It was not expected to blame file %s",
        file.relativePath());

    if (lines.size() != file.lines()) {
      LOG.debug(
          "Ignoring blame result since provider returned {} blame lines but file {} has {} lines",
          lines.size(),
          file.relativePath(),
          file.lines());
      return;
    }

    BatchComponent batchComponent = componentCache.get(file);
    Builder scmBuilder = BatchReport.Changesets.newBuilder();
    scmBuilder.setComponentRef(batchComponent.batchId());
    Map<String, Integer> changesetsIdByRevision = new HashMap<>();

    int lineId = 1;
    for (BlameLine line : lines) {
      validateLine(line, lineId, file);
      Integer changesetId = changesetsIdByRevision.get(line.revision());
      if (changesetId == null) {
        addChangeset(scmBuilder, line);
        changesetId = scmBuilder.getChangesetCount() - 1;
        changesetsIdByRevision.put(line.revision(), changesetId);
      }
      scmBuilder.addChangesetIndexByLine(changesetId);
      lineId++;
    }
    writer.writeComponentChangesets(scmBuilder.build());
    allFilesToBlame.remove(file);
    count++;
    progressReport.message(count + "/" + total + " files analyzed");
  }