private async updateStatus()

in functions/src/plugins/merge.ts [405:547]


  private async updateStatus(context: Context, config?: MergeConfig, updateStatus = true, labels?: Github.PullRequestsGetResponseLabelsItem[], statuses?: GithubGQL.StatusContext[]): Promise<void> {
    let updateG3Status = false;
    if(context.payload.action === "synchronize") {
      updateG3Status = true;
    }
    if(!updateStatus && !updateG3Status) {
      return;
    }
    config = config || await this.getConfig(context);
    if(config.status.disabled) {
      return;
    }
    let sha, pr;
    const {owner, repo} = context.repo();

    switch(context.name) {
      case 'pull_request':
      case 'pull_request_review':
        sha = context.payload.pull_request.head.sha;
        pr = context.payload.pull_request;
        pr = await this.updateDbPR(context.github, owner, repo, pr.number, context.payload.repository.id, pr).catch(err => {
          throw err;
        });
        if(!labels) {
          labels = pr.labels || await this.getPRLabels(context);
        }
        break;
      case 'status':
        // Ignore status update events that are coming from this bot
        if(context.payload.context === config.status.context) {
          this.logDebug({context}, `Update status coming from this bot, ignored`);
          return;
        }
        // Ignore status events for commits coming directly from the default branch (most likely using github edit)
        // because they are not coming from a PR (e.g. travis runs for all commits and triggers a status update)
        if(context.payload.branches.name === context.payload.repository.default_branch) {
          this.logDebug({context}, `Update status coming directly from the default branch (${context.payload.branches.name}), ignored`);
          return;
        }
        sha = context.payload.sha;
        pr = await this.findPrBySha(sha, context.payload.repository.id);

        if(!pr) {
          // The repository data was previously stored as a simple id, checking if this PR still has old data
          const matches = (await this.pullRequests.where('head.sha', '==', sha)
            .where('repository', '==', context.payload.repository.id)
            .get());
          matches.forEach(async doc => {
            pr = doc.data();
          });
        }
        // Either init has not finished yet and we don't have this PR in the DB, or it's a status update for a commit
        // made directly on a branch without a PR (e.g. travis runs for all commits and triggers a status update)
        if(!pr) {
          this.logWarn({context}, `Update status for unknown PR, ignored. Head sha == ${sha}, repository == ${context.payload.repository.id}`);
          return;
        } else {
          // make sure that we have updated data
          pr = await this.updateDbPR(context.github, owner, repo, pr.number, context.payload.repository.id);
        }
        if(!labels) {
          labels = pr.labels || await getGhPRLabels(context.github, owner, repo, pr.number);
        }
        break;
      default:
        throw new Error(`Unhandled event ${context.name} in updateStatus`);
    }

    statuses = statuses || await this.getStatuses(context, pr.number, config);

    if(config.g3Status && !config.g3Status.disabled && (updateG3Status ||
      // Check if the g3status is missing
      !statuses.some(status => status.context === config.g3Status.context)
    )) {
      // Checking if we need to add g3 status
      const files: Github.PullRequestsListFilesResponse = await context.github.paginate(
        context.github.pullRequests.listFiles({owner, repo, number: pr.number}),
        pages => (pages as any).data) as Github.PullRequestsListFilesResponse;
      (await context.github.pullRequests.listFiles({owner, repo, number: pr.number})).data;
      if(this.matchAnyFile(files.map(file => file.filename), config.g3Status.include, config.g3Status.exclude)) {
        // Only update g3 status if a commit was just pushed, or there was no g3 status
        if(context.payload.action === "synchronize" || !statuses.some(status => status.context === config.g3Status.context)) {
          const status = (await context.github.repos.createStatus({
            owner,
            repo,
            sha: sha,
            context: config.g3Status.context,
            state: STATUS_STATE.Pending,
            description: config.g3Status.pendingDesc.replace("{{PRNumber}}", pr.number),
            target_url: config.g3Status.url
          })).data as any as GithubGQL.StatusContext;
          statuses.push(status);
          this.log({context}, `Updated g3 status to pending`);
        }
      } else {
        const status = (await context.github.repos.createStatus({
          owner,
          repo,
          sha: pr.head.sha,
          context: config.g3Status.context,
          state: STATUS_STATE.Success,
          description: config.g3Status.successDesc
        })).data as any as GithubGQL.StatusContext;
        statuses.push(status);
        this.log({context}, `Updated g3 status to success`);
      }
    }

    if(updateStatus) {
      const statusParams: Github.ReposCreateStatusParams = {
        owner,
        repo,
        sha: sha,
        context: config.status.context,
        state: STATUS_STATE.Success
      };

      const failedChecks = await this.getChecksStatus(context, pr, config, labels, statuses);

      if(failedChecks.failure.length > 0) {
        statusParams.state = STATUS_STATE.Failure;
        statusParams.description = failedChecks.failure.concat(failedChecks.pending).join(', ');
      } else if(failedChecks.pending.length > 0) {
        statusParams.state = STATUS_STATE.Pending;
        statusParams.description = failedChecks.pending.join(', ');
      } else {
        statusParams.state = STATUS_STATE.Success;
        statusParams.description = config.status.successText;
      }

      // Capitalize first letter
      statusParams.description = statusParams.description.replace(statusParams.description[0], statusParams.description[0].toUpperCase());
      const desc = statusParams.description;

      // TODO(ocombe): add a link to a dynamic page with the complete status & some description of what's required
      if(statusParams.description.length > 140) {
        statusParams.description = statusParams.description.substring(0, 137) + '...';
      }

      await context.github.repos.createStatus(statusParams);
      this.log({context}, `Updated status to "${statusParams.state}": ${desc}`);
    }
  }