public PullRequestData addPullRequestData(GHPullRequest pullRequest, AbstractProject project)
      throws IOException {

    ConcurrentHashMap<String, PullRequestData> pullRequestDataMap =
        projectPullRequestDataLookup.get(project);

    if (pullRequestDataMap == null) {
      projectPullRequestDataLookup.putIfAbsent(
          project, new ConcurrentHashMap<String, PullRequestData>());
      pullRequestDataMap = projectPullRequestDataLookup.get(project);
    }

    PullRequestData data = pullRequestDataMap.get(pullRequest.getHtmlUrl().toString());
    if (data == null) {

      String pullRequestUrl = pullRequest.getHtmlUrl().toString();

      PullRequestData newPullRequestData =
          new PullRequestData(pullRequest, ProjectData.getInstance(project, true));

      pullRequestDataMap.putIfAbsent(pullRequestUrl, newPullRequestData);

      data = pullRequestDataMap.get(pullRequestUrl);

      if (data == newPullRequestData) {
        data.save();
      }
    }

    return data;
  }
    @Override
    public void onDeploying(AbstractBuild<?, ?> build, String instanceId, ElasticBoxCloud cloud)
        throws IOException, InterruptedException {

      AbstractBuild<?, ?> rootBuild = build;
      for (Cause.UpstreamCause upstreamCause = build.getCause(Cause.UpstreamCause.class);
          upstreamCause != null;
          upstreamCause = rootBuild.getCause(Cause.UpstreamCause.class)) {
        Run<?, ?> run = upstreamCause.getUpstreamRun();
        if (run == null) {
          break;
        }
        rootBuild = (AbstractBuild<?, ?>) run;
      }

      TriggerCause cause = rootBuild.getCause(TriggerCause.class);
      if (cause == null) {
        return;
      }

      ConcurrentHashMap<String, PullRequestData> prDataLookup =
          getInstance().projectPullRequestDataLookup.get(rootBuild.getProject());

      if (prDataLookup != null) {
        PullRequestData data = prDataLookup.get(cause.getPullRequest().getHtmlUrl().toString());
        if (data == null) {
          data = getInstance().addPullRequestData(cause.getPullRequest(), rootBuild.getProject());
        }
        data.getInstances().add(new PullRequestInstance(instanceId, cloud.name));
        data.save();
      }
    }
    @Override
    public void onTerminating(AbstractBuild<?, ?> build, String instanceId, ElasticBoxCloud cloud)
        throws IOException, InterruptedException {

      final Collection<ConcurrentHashMap<String, PullRequestData>> values =
          getInstance().projectPullRequestDataLookup.values();

      for (ConcurrentHashMap<String, PullRequestData> prDataLookup : values) {
        for (PullRequestData data : prDataLookup.values()) {
          for (Iterator<PullRequestInstance> it = data.getInstances().iterator(); it.hasNext(); ) {
            if (it.next().id.equals(instanceId)) {
              it.remove();
              data.save();
              return;
            }
          }
        }
      }
    }
  void handle(GHEventPayload.PullRequest prEventPayload, GitHub gitHub) throws IOException {
    GHPullRequest pullRequest = prEventPayload.getPullRequest();
    String pullRequestUrl = pullRequest.getHtmlUrl().toString();
    if (!pullRequestUrl.startsWith(gitHubRepositoryUrl)) {
      LOGGER.config(
          MessageFormat.format(
              "Pull request {0} is not related to project {1}. "
                  + "GitHub project URL configured for project {1}: {2}",
              pullRequestUrl, project.getFullName(), gitHubRepositoryUrl));
      return;
    }

    LOGGER.info(
        MessageFormat.format(
            "Handling event ''{0}'' of pull request {1} for project {2}",
            prEventPayload.getAction(), pullRequestUrl, project.getFullName()));

    PullRequestManager pullRequestManager = PullRequestManager.getInstance();
    PullRequestData pullRequestData =
        pullRequestManager.getPullRequestData(pullRequestUrl, project);

    if (PullRequestManager.PullRequestAction.CLOSED.equals(prEventPayload.getAction())) {
      if (pullRequestData != null) {
        cancelBuilds(pullRequestData);
        deleteInstances(pullRequest);
      } else {
        LOGGER.warning(
            "No previous data available for received Pull Request 'close' event: "
                + pullRequestUrl);
      }
      return;
    }

    if (!isWhitelisted(pullRequest.getUser(), gitHub)) {
      LOGGER.info(
          MessageFormat.format(
              "GitHub user {0} is not in the whitelist of project {1}",
              pullRequest.getUser().getLogin(), project.getFullName()));

      return;
    }

    boolean startBuild = false;

    if (pullRequestData == null) {
      if (PullRequestManager.PullRequestAction.SYNCHRONIZE.equals(prEventPayload.getAction())) {
        LOGGER.info(
            MessageFormat.format(
                "Updated pull request {0} was not built previously", pullRequestUrl));
      }
      pullRequestData = pullRequestManager.addPullRequestData(pullRequest, project);
      startBuild = pullRequestData.getLastUpdated().equals(pullRequest.getUpdatedAt());

    } else if (pullRequestData.update(pullRequest)) {
      pullRequestData.save();
      startBuild = true;
    }

    if (LOGGER.isLoggable(Level.FINEST)) {
      LOGGER.finest("Received event payload: " + prEventPayload);
    }

    if (startBuild) {
      if (LOGGER.isLoggable(Level.FINE)) {
        LOGGER.fine(
            "Cancelling previous running builds and starting new build for Pull request: "
                + pullRequestData);
      }
      cancelBuilds(pullRequestData);
      build(pullRequest, null, new TriggerCause(prEventPayload));

    } else if (LOGGER.isLoggable(Level.FINE)) {
      LOGGER.fine("No new build has been triggered for Pull request: " + pullRequestData);
    }
  }