public CreatePullRequestModel(
      @NotNull final Project project, @NotNull final GitRepository gitRepository) {
    this.project = project;
    this.gitRepository = gitRepository;

    this.tfGitRemotes = TfGitHelper.getTfGitRemotes(gitRepository);

    this.remoteBranchComboModel = createRemoteBranchDropdownModel();
    this.targetBranch = (GitRemoteBranch) this.remoteBranchComboModel.getSelectedItem();

    this.applicationProvider = new ApplicationProvider();
    this.pullRequestHelper = new PullRequestHelper();

    this.diffCompareInfoProvider = new DiffCompareInfoProvider();
    this.diffCache =
        CacheBuilder.newBuilder()
            .maximumSize(20)
            .build(
                new CacheLoader<Pair<String, String>, GitCommitCompareInfo>() {
                  @Override
                  public GitCommitCompareInfo load(Pair<String, String> key) throws Exception {
                    // if we missed the cache, then show the loading spinner, otherwise
                    // just switch to the diff we have to avoid flickering the screen
                    applicationProvider.invokeAndWaitWithAnyModality(
                        new Runnable() {
                          @Override
                          public void run() {
                            // set the view to show loading
                            setLoading(true);
                          }
                        });

                    return getDiffCompareInfoProvider()
                        .getBranchCompareInfo(
                            project, gitRepository, key.getFirst(), key.getSecond());
                  }
                });

    this.executorService = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
  }
  /**
   * Create pull request on a background thread
   *
   * <p>This method will first check to see if the local branch has a tracking branch: yes: push the
   * commits to the remote tracking branch no: try create a remote branch matching the local branch
   * name exactly, with the remote set to the GitRemote of the target branch
   *
   * <p>If push fails for whatever reason, stop and show an error message
   *
   * <p>After we push the local branch, then create the pull request. Pull request link should be
   * returned in a notification bubble
   */
  public void createPullRequest() {
    /* verifying branch selections */
    final GitLocalBranch sourceBranch = this.getSourceBranch();
    final GitRemoteBranch targetBranch = this.getTargetBranch();

    if (sourceBranch == null) {
      // how did we get here? validation failed?
      notifyCreateFailedError(
          project, TfPluginBundle.message(TfPluginBundle.KEY_CREATE_PR_ERRORS_SOURCE_EMPTY));
      return;
    }

    if (targetBranch == null) {
      // how did we get here? validation failed?
      notifyCreateFailedError(
          project, TfPluginBundle.message(TfPluginBundle.KEY_CREATE_PR_ERRORS_TARGET_NOT_SELECTED));
      return;
    }

    if (targetBranch.equals(this.getRemoteTrackingBranch())) {
      // how did we get here? Didn't we filter you out?
      notifyCreateFailedError(
          project,
          TfPluginBundle.message(TfPluginBundle.KEY_CREATE_PR_ERRORS_TARGET_IS_LOCAL_TRACKING));
      return;
    }

    // TODO Determine the correct/best way to get the remote url
    final String gitRemoteUrl = TfGitHelper.getTfGitRemote(gitRepository).getFirstUrl();
    final CreatePullRequestModel createModel = this;
    /* Let's keep all server interactions to a background thread */
    final Task.Backgroundable createPullRequestTask =
        new Task.Backgroundable(
            project,
            TfPluginBundle.message(TfPluginBundle.KEY_CREATE_PR_DIALOG_TITLE),
            true,
            PerformInBackgroundOption.DEAF) {
          @Override
          public void run(@NotNull ProgressIndicator progressIndicator) {
            // get context from manager, create PAT if needed, and store in active context
            final ServerContext context =
                ServerContextManager.getInstance()
                    .getAuthenticatedContext(
                        gitRemoteUrl,
                        TfPluginBundle.message(TfPluginBundle.KEY_PAT_TOKEN_DESC),
                        true);

            if (context == null) {
              notifyCreateFailedError(
                  project,
                  TfPluginBundle.message(
                      TfPluginBundle.KEY_ERRORS_AUTH_NOT_SUCCESSFUL, gitRemoteUrl));
              return;
            }

            ListenableFuture<Pair<String, GitCommandResult>> pushResult =
                doPushCommits(
                    gitRepository, sourceBranch, targetBranch.getRemote(), progressIndicator);

            Futures.addCallback(
                pushResult,
                new FutureCallback<Pair<String, GitCommandResult>>() {
                  @Override
                  public void onSuccess(@Nullable Pair<String, GitCommandResult> result) {
                    if (result != null && StringUtils.isNotEmpty(result.getFirst())) {
                      final String title = createModel.getTitle();
                      final String description = createModel.getDescription();
                      final String branchNameOnRemoteServer = result.getFirst();

                      doCreatePullRequest(
                          project,
                          context,
                          title,
                          description,
                          branchNameOnRemoteServer,
                          targetBranch);
                    } else {
                      // I really don't have anything else to say, push failed, the title says it
                      // all
                      // I have no error message to be more specific
                      notifyPushFailedError(createModel.getProject(), StringUtils.EMPTY);
                    }
                  }

                  @Override
                  public void onFailure(Throwable t) {
                    notifyPushFailedError(createModel.getProject(), t.getLocalizedMessage());
                  }
                });
          }
        };

    createPullRequestTask.queue();
  }