@ShellMethod(key = "diff file", value = "Check how file differs across range of commits")
  public String diffFile(
      @ShellOption(value = {"--fileId"}, help = "File ID to diff across range of commits") String fileId,
      @ShellOption(value = {"--startTs"}, help = "start time for compactions, default: now - 10 days",
          defaultValue = ShellOption.NULL) String startTs,
      @ShellOption(value = {"--endTs"}, help = "end time for compactions, default: now - 1 day",
          defaultValue = ShellOption.NULL) String endTs,
      @ShellOption(value = {"--limit"}, help = "Limit compactions", defaultValue = "-1") final Integer limit,
      @ShellOption(value = {"--sortBy"}, help = "Sorting Field", defaultValue = "") final String sortByField,
      @ShellOption(value = {"--desc"}, help = "Ordering", defaultValue = "false") final boolean descending,
      @ShellOption(value = {"--headeronly"}, help = "Print Header Only", defaultValue = "false") final boolean headerOnly,
      @ShellOption(value = {"--includeArchivedTimeline"}, help = "Include archived commits as well",
          defaultValue = "false") final boolean includeArchivedTimeline) throws IOException {
    HoodieDefaultTimeline timeline = CLIUtils.getTimelineInRange(startTs, endTs, includeArchivedTimeline);
    return printCommitsWithMetadataForFileId(timeline, limit, sortByField, descending, headerOnly, "", fileId);
  }
@Test
  public void testDiffFile() throws Exception {
    // create COW table.
    new TableCommand().createTable(
        tablePath, tableName, HoodieTableType.COPY_ON_WRITE.name(),
        "", TimelineLayoutVersion.VERSION_1, HoodieAvroPayload.class.getName());

    StorageConfiguration<?> conf = HoodieCLI.conf;

    HoodieTableMetaClient metaClient = HoodieCLI.getTableMetaClient();
    String fileId1 = UUID.randomUUID().toString();
    String fileId2 = UUID.randomUUID().toString();
    HoodieStorage storage = HoodieStorageUtils.getStorage(basePath(), storageConf());
    HoodieTestDataGenerator.writePartitionMetadataDeprecated(storage,
        HoodieTestDataGenerator.DEFAULT_PARTITION_PATHS, tablePath);

    // Create four commits
    Set<String> commits = new HashSet<>();
    for (int i = 100; i < 104; i++) {
      String timestamp = String.valueOf(i);
      commits.add(timestamp);
      // Requested Compaction
      HoodieTestCommitMetadataGenerator.createCompactionAuxiliaryMetadata(tablePath,
          new HoodieInstant(HoodieInstant.State.REQUESTED, HoodieTimeline.COMPACTION_ACTION, timestamp), conf);
      // Inflight Compaction
      HoodieTestCommitMetadataGenerator.createCompactionAuxiliaryMetadata(tablePath,
          new HoodieInstant(HoodieInstant.State.INFLIGHT, HoodieTimeline.COMPACTION_ACTION, timestamp), conf);

      Map<String, String> extraCommitMetadata =
          Collections.singletonMap(HoodieCommitMetadata.SCHEMA_KEY, HoodieTestTable.PHONY_TABLE_SCHEMA);
      HoodieTestCommitMetadataGenerator.createCommitFileWithMetadata(tablePath, timestamp, conf, fileId1, fileId2,
          Option.empty(), Option.empty(), extraCommitMetadata, false);
    }

    HoodieTableMetaClient.reload(metaClient);

    Object result =  shell.evaluate(() -> String.format("diff file --fileId %s", fileId1));
    assertTrue(ShellEvaluationResultUtil.isSuccess(result));
    String expected = generateExpectDataWithExtraMetadata(commits, fileId1, HoodieTestDataGenerator.DEFAULT_FIRST_PARTITION_PATH);
    expected = removeNonWordAndStripSpace(expected);
    String got = removeNonWordAndStripSpace(result.toString());
    assertEquals(expected, got);
  }