public boolean checkAction(@Nullable final BranchInfo branch) {
    if (branch == null) {
      GithubNotifications.showWarningDialog(
          myProject, CANNOT_CREATE_PULL_REQUEST, "Target branch is not selected");
      return false;
    }

    DiffInfo info;
    try {
      info =
          GithubUtil.computeValueInModal(
              myProject,
              "Collecting diff data...",
              new ThrowableConvertor<ProgressIndicator, DiffInfo, IOException>() {
                @Override
                public DiffInfo convert(ProgressIndicator indicator) throws IOException {
                  return GithubUtil.runInterruptable(
                      indicator,
                      new ThrowableComputable<DiffInfo, IOException>() {
                        @Override
                        public DiffInfo compute() throws IOException {
                          return getDiffInfo(branch);
                        }
                      });
                }
              });
    } catch (IOException e) {
      GithubNotifications.showError(myProject, "Can't collect diff data", e);
      return true;
    }
    if (info == null) {
      return true;
    }

    ForkInfo fork = branch.getForkInfo();

    String localBranchName = "'" + myCurrentBranch + "'";
    String targetBranchName = "'" + fork.getRemoteName() + "/" + branch.getRemoteName() + "'";
    if (info.getInfo().getBranchToHeadCommits(myGitRepository).isEmpty()) {
      return GithubNotifications.showYesNoDialog(
          myProject,
          "Do you want to proceed anyway?",
          "Empty pull request: the branch "
              + localBranchName
              + " is fully merged to the branch "
              + targetBranchName);
    }
    if (!info.getInfo().getHeadToBranchCommits(myGitRepository).isEmpty()) {
      return GithubNotifications.showYesNoDialog(
          myProject,
          "Do you want to proceed anyway?",
          "The branch "
              + targetBranchName
              + " is not fully merged to the branch "
              + localBranchName);
    }

    return true;
  }
 public void configureRemote(@NotNull final ForkInfo fork) {
   GithubUtil.computeValueInModal(
       myProject,
       "Creating remote..",
       false,
       new Consumer<ProgressIndicator>() {
         @Override
         public void consume(ProgressIndicator indicator) {
           doConfigureRemote(fork);
         }
       });
 }
  @Nullable
  public ForkInfo showTargetDialog() {
    if (myAvailableForks == null) {
      myAvailableForks =
          GithubUtil.computeValueInModal(
              myProject,
              myCurrentBranch,
              new Convertor<ProgressIndicator, List<GithubFullPath>>() {
                @Override
                public List<GithubFullPath> convert(ProgressIndicator indicator) {
                  return getAvailableForks(indicator);
                }
              });
    }

    Convertor<String, ForkInfo> getForkPath =
        new Convertor<String, ForkInfo>() {
          @Nullable
          @Override
          public ForkInfo convert(@NotNull final String user) {
            return GithubUtil.computeValueInModal(
                myProject,
                "Access to GitHub",
                new Convertor<ProgressIndicator, ForkInfo>() {
                  @Nullable
                  @Override
                  public ForkInfo convert(ProgressIndicator indicator) {
                    return findRepositoryByUser(indicator, user);
                  }
                });
          }
        };
    GithubSelectForkDialog dialog =
        new GithubSelectForkDialog(myProject, myAvailableForks, getForkPath);
    DialogManager.show(dialog);
    if (!dialog.isOK()) {
      return null;
    }
    return dialog.getPath();
  }
  public void showDiffDialog(@Nullable final BranchInfo branch) {
    if (branch == null) {
      GithubNotifications.showWarningDialog(
          myProject, "Can't Show Diff", "Target branch is not selected");
      return;
    }

    DiffInfo info;
    try {
      info =
          GithubUtil.computeValueInModal(
              myProject,
              "Collecting diff data...",
              new ThrowableConvertor<ProgressIndicator, DiffInfo, IOException>() {
                @Override
                public DiffInfo convert(ProgressIndicator indicator) throws IOException {
                  return GithubUtil.runInterruptable(
                      indicator,
                      new ThrowableComputable<DiffInfo, IOException>() {
                        @Override
                        public DiffInfo compute() throws IOException {
                          return getDiffInfo(branch);
                        }
                      });
                }
              });
    } catch (IOException e) {
      GithubNotifications.showError(myProject, "Can't collect diff data", e);
      return;
    }
    if (info == null) {
      GithubNotifications.showErrorDialog(myProject, "Can't Show Diff", "Can't collect diff data");
      return;
    }

    GitCompareBranchesDialog dialog =
        new GitCompareBranchesDialog(
            myProject, info.getTo(), info.getFrom(), info.getInfo(), myGitRepository, true);
    dialog.show();
  }
  @NotNull
  public Couple<String> getDefaultDescriptionMessage(@NotNull final BranchInfo branch) {
    Couple<String> message = branch.getDefaultMessage();
    if (message != null) return message;

    if (branch.getForkInfo().getRemoteName() == null) {
      return getSimpleDefaultDescriptionMessage(branch);
    }

    return GithubUtil.computeValueInModal(
        myProject,
        "Collecting additional data...",
        false,
        new Convertor<ProgressIndicator, Couple<String>>() {
          @Override
          public Couple<String> convert(ProgressIndicator o) {
            String localBranch = myCurrentBranch;
            String targetBranch =
                branch.getForkInfo().getRemoteName() + "/" + branch.getRemoteName();
            try {
              List<VcsCommitMetadata> commits =
                  GitHistoryUtils.readLastCommits(
                      myProject, myGitRepository.getRoot(), localBranch, targetBranch);
              if (commits == null) return getSimpleDefaultDescriptionMessage(branch);

              VcsCommitMetadata localCommit = commits.get(0);
              VcsCommitMetadata targetCommit = commits.get(1);

              if (localCommit.getParents().contains(targetCommit.getId())) {
                return Couple.of(localCommit.getSubject(), localCommit.getFullMessage());
              }
              return getSimpleDefaultDescriptionMessage(branch);
            } catch (VcsException e) {
              GithubNotifications.showWarning(myProject, "Can't collect additional data", e);
              return getSimpleDefaultDescriptionMessage(branch);
            }
          }
        });
  }
  @Nullable
  public static GithubCreatePullRequestWorker create(
      @NotNull final Project project, @Nullable final VirtualFile file) {
    return GithubUtil.computeValueInModal(
        project,
        "Loading data...",
        new Convertor<ProgressIndicator, GithubCreatePullRequestWorker>() {
          @Override
          public GithubCreatePullRequestWorker convert(ProgressIndicator indicator) {
            Git git = ServiceManager.getService(Git.class);

            GitRepository gitRepository = GithubUtil.getGitRepository(project, file);
            if (gitRepository == null) {
              GithubNotifications.showError(
                  project, CANNOT_CREATE_PULL_REQUEST, "Can't find git repository");
              return null;
            }
            gitRepository.update();

            Pair<GitRemote, String> remote = GithubUtil.findGithubRemote(gitRepository);
            if (remote == null) {
              GithubNotifications.showError(
                  project, CANNOT_CREATE_PULL_REQUEST, "Can't find GitHub remote");
              return null;
            }
            String remoteName = remote.getFirst().getName();
            String remoteUrl = remote.getSecond();

            GithubFullPath path = GithubUrlUtil.getUserAndRepositoryFromRemoteUrl(remoteUrl);
            if (path == null) {
              GithubNotifications.showError(
                  project, CANNOT_CREATE_PULL_REQUEST, "Can't process remote: " + remoteUrl);
              return null;
            }

            GitLocalBranch currentBranch = gitRepository.getCurrentBranch();
            if (currentBranch == null) {
              GithubNotifications.showError(
                  project, CANNOT_CREATE_PULL_REQUEST, "No current branch");
              return null;
            }

            GithubAuthDataHolder authHolder;
            try {
              authHolder = GithubUtil.getValidAuthDataHolderFromConfig(project, indicator);
            } catch (IOException e) {
              GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, e);
              return null;
            }

            GithubCreatePullRequestWorker worker =
                new GithubCreatePullRequestWorker(
                    project,
                    git,
                    gitRepository,
                    authHolder,
                    path,
                    remoteName,
                    remoteUrl,
                    currentBranch.getName());

            try {
              worker.initForks(indicator);
            } catch (IOException e) {
              GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, e);
              return null;
            }

            return worker;
          }
        });
  }