Repository: runatlantis/atlantis (language: go)

Issue:
Apply Failed: Pull request must be mergeable before running apply
### Overview

`atlantis apply` fails with message `Pull request must be mergeable before running apply`

### Reproduction Steps

1. Create GitHub PR
2. Run plan and have all PR checks be green
3. Run apply

### Logs

<details>
  <summary>Logs</summary>

```
{"level":"debug","ts":"2022-06-09T12:07:44.719Z","caller":"events/events_controller.go:98","msg":"handling GitHub post","json":{}}
{"level":"debug","ts":"2022-06-09T12:07:44.720Z","caller":"events/events_controller.go:163","msg":"request valid","json":{"gh-request-id":"X-Github-Delivery=c4871d10-e7ec-11ec-88d4-0a3aead7c5cc"}}
{"level":"info","ts":"2022-06-09T12:07:44.720Z","caller":"events/events_controller.go:533","msg":"parsed comment as command=\"apply\" verbose=false dir=\"\" workspace=\"\" project=\"\" flags=\"\"","json":{"gh-request-id":"X-Github-Delivery=c4871d10-e7ec-11ec-88d4-0a3aead7c5cc"}}
{"level":"debug","ts":"2022-06-09T12:07:44.720Z","caller":"events/events_controller.go:563","msg":"executing command","json":{"gh-request-id":"X-Github-Delivery=c4871d10-e7ec-11ec-88d4-0a3aead7c5cc"}}
{"level":"debug","ts":"2022-06-09T12:07:44.720Z","caller":"server/middleware.go:70","msg":"POST /events – respond HTTP 200","json":{}}
{"level":"debug","ts":"2022-06-09T12:07:44.737Z","caller":"metrics/debug.go:42","msg":"counter","json":{"name":"atlantis.github.event.comment.created.success_200","value":1,"tags":{},"type":"counter"}}
{"level":"debug","ts":"2022-06-09T12:07:45.010Z","caller":"metrics/debug.go:52","msg":"timer","json":{"name":"atlantis.github.get_pull_request.execution_time","value":0.289719565,"tags":{},"type":"timer"}}
{"level":"debug","ts":"2022-06-09T12:07:45.011Z","caller":"events/pre_workflow_hooks_command_runner.go:48","msg":"pre-hooks configured, running...","json":{"repo":"org/repo","pull":"2644"}}
{"level":"debug","ts":"2022-06-09T12:07:45.011Z","caller":"events/pre_workflow_hooks_command_runner.go:54","msg":"got workspace lock","json":{"repo":"org/repo","pull":"2644"}}
{"level":"info","ts":"2022-06-09T12:07:45.011Z","caller":"events/github_app_working_dir.go:26","msg":"Refreshing git tokens for Github App","json":{"repo":"org/repo","pull":"2644"}}
{"level":"debug","ts":"2022-06-09T12:07:45.011Z","caller":"events/git_cred_writer.go:36","msg":"git credentials file has expected contents, not modifying","json":{"repo":"org/repo","pull":"2644"}}
{"level":"debug","ts":"2022-06-09T12:07:45.011Z","caller":"events/working_dir.go:90","msg":"clone directory \"/atlantis-data/repos/org/repo/2644/default\" already exists, checking if it's at the right commit","json":{"repo":"org/repo","pull":"2644"}}
{"level":"debug","ts":"2022-06-09T12:07:45.017Z","caller":"events/working_dir.go:113","msg":"repo is at correct commit \"ae343891f6b29260d91cbd0462ca065c89572389\" so will not re-clone","json":{"repo":"org/repo","pull":"2644"}}
{"level":"info","ts":"2022-06-09T12:07:45.021Z","caller":"runtime/pre_workflow_hook_runner.go:50","msg":"successfully ran \"rm -rf /tmp/$BASE_REPO_OWNER-$BASE_REPO_NAME-$PULL_NUM\" in \"/atlantis-data/repos/org/repo/2644/default\"","json":{"repo":"org/repo","pull":"2644"}}
{"level":"info","ts":"2022-06-09T12:07:45.024Z","caller":"runtime/pre_workflow_hook_runner.go:50","msg":"successfully ran \"mkdir -p /tmp/$BASE_REPO_OWNER-$BASE_REPO_NAME-$PULL_NUM\" in \"/atlantis-data/repos/org/repo/2644/default\"","json":{"repo":"org/repo","pull":"2644"}}
{"level":"info","ts":"2022-06-09T12:07:54.211Z","caller":"runtime/pre_workflow_hook_runner.go:50","msg":"successfully ran \"some_command\\n\" in \"/atlantis-data/repos/org/repo/2644/default\"","json":{"repo":"org/repo","pull":"2644"}}
{"level":"debug","ts":"2022-06-09T12:07:54.490Z","caller":"metrics/debug.go:52","msg":"timer","json":{"name":"atlantis.github.update_status.execution_time","value":0.278190053,"tags":{},"type":"timer"}}
{"level":"debug","ts":"2022-06-09T12:07:54.490Z","caller":"vcs/github_client.go:277","msg":"GET /repos/org/repo/pulls/2644/reviews","json":{}}
{"level":"debug","ts":"2022-06-09T12:07:54.686Z","caller":"metrics/debug.go:52","msg":"timer","json":{"name":"atlantis.github.pull_is_approved.execution_time","value":0.195903945,"tags":{},"type":"timer"}}
{"level":"debug","ts":"2022-06-09T12:07:54.738Z","caller":"metrics/debug.go:42","msg":"counter","json":{"name":"atlantis.github.pull_is_approved.execution_success","value":1,"tags":{},"type":"counter"}}
{"level":"debug","ts":"2022-06-09T12:07:54.738Z","caller":"metrics/debug.go:42","msg":"counter","json":{"name":"atlantis.github.update_status.execution_success","value":1,"tags":{},"type":"counter"}}
{"level":"debug","ts":"2022-06-09T12:07:54.931Z","caller":"metrics/debug.go:52","msg":"timer","json":{"name":"atlantis.github.pull_is_mergeable.execution_time","value":0.244855955,"tags":{},"type":"timer"}}
{"level":"debug","ts":"2022-06-09T12:07:54.943Z","caller":"valid/global_cfg.go:312","msg":"building config based on server-side config","json":{"repo":"org/repo","pull":"2644"}}
{"level":"debug","ts":"2022-06-09T12:07:54.943Z","caller":"valid/global_cfg.go:481","msg":"setting apply_requirements: [approved,mergeable] from repos[1], id: /.*/","json":{"repo":"org/repo","pull":"2644"}}
{"level":"debug","ts":"2022-06-09T12:07:54.944Z","caller":"valid/global_cfg.go:481","msg":"setting workflow: \"default\" from repos[1], id: /.*/","json":{"repo":"org/repo","pull":"2644"}}
{"level":"debug","ts":"2022-06-09T12:07:54.944Z","caller":"valid/global_cfg.go:481","msg":"setting allowed_overrides: [] from default server config","json":{"repo":"org/repo","pull":"2644"}}
{"level":"debug","ts":"2022-06-09T12:07:54.945Z","caller":"valid/global_cfg.go:481","msg":"setting allow_custom_workflows: false from repos[1], id: /.*/","json":{"repo":"org/repo","pull":"2644"}}
{"level":"debug","ts":"2022-06-09T12:07:54.945Z","caller":"valid/global_cfg.go:481","msg":"setting delete_source_branch_on_merge: false from repos[1], id: /.*/","json":{"repo":"org/repo","pull":"2644"}}
{"level":"debug","ts":"2022-06-09T12:07:54.946Z","caller":"events/project_command_context_builder.go:95","msg":"Building project command context for apply","json":{"repo":"org/repo","pull":"2644"}}
{"level":"debug","ts":"2022-06-09T12:07:54.969Z","caller":"events/project_command_context_builder.go:302","msg":"did not specify exact version in terraform configuration, found \"~> 0.13.0\"","json":{"repo":"org/repo","pull":"2644"}}
{"level":"debug","ts":"2022-06-09T12:07:54.969Z","caller":"metrics/debug.go:52","msg":"timer","json":{"name":"atlantis.cmd.comment.apply.builder.execution_time","value":0.038250258,"tags":{},"type":"timer"}}
{"level":"debug","ts":"2022-06-09T12:07:55.246Z","caller":"metrics/debug.go:52","msg":"timer","json":{"name":"atlantis.github.update_status.execution_time","value":0.276282191,"tags":{},"type":"timer"}}
{"level":"debug","ts":"2022-06-09T12:07:55.562Z","caller":"metrics/debug.go:52","msg":"timer","json":{"name":"atlantis.github.update_status.execution_time","value":0.316057224,"tags":{},"type":"timer"}}
{"level":"error","ts":"2022-06-09T12:07:55.562Z","caller":"events/instrumented_project_command_runner.go:49","msg":"Failure running apply operation: Pull request must be mergeable before running apply.","json":{"repo":"org/repo","pull":"2644"},"stacktrace":"github.com/runatlantis/atlantis/server/events.RunAndEmitStats\n\tgithub.com/runatlantis/atlantis/server/events/instrumented_project_command_runner.go:49\ngithub.com/runatlantis/atlantis/server/events.(*InstrumentedProjectCommandRunner).Apply\n\tgithub.com/runatlantis/atlantis/server/events/instrumented_project_command_runner.go:21\ngithub.com/runatlantis/atlantis/server/events.runProjectCmds\n\tgithub.com/runatlantis/atlantis/server/events/project_command_pool_executor.go:47\ngithub.com/runatlantis/atlantis/server/events.(*ApplyCommandRunner).Run\n\tgithub.com/runatlantis/atlantis/server/events/apply_command_runner.go:147\ngithub.com/runatlantis/atlantis/server/events.(*DefaultCommandRunner).RunCommentCommand\n\tgithub.com/runatlantis/atlantis/server/events/command_runner.go:277"}
{"level":"debug","ts":"2022-06-09T12:07:55.562Z","caller":"metrics/debug.go:52","msg":"timer","json":{"name":"atlantis.cmd.comment.apply.execution_time","value":0.592968884,"tags":{},"type":"timer"}}
{"level":"debug","ts":"2022-06-09T12:07:55.562Z","caller":"vcs/github_client.go:209","msg":"GET /repos/org/repo/issues/2644/comments","json":{}}
{"level":"debug","ts":"2022-06-09T12:07:55.738Z","caller":"metrics/debug.go:42","msg":"counter","json":{"name":"atlantis.cmd.comment.apply.execution_failure","value":1,"tags":{},"type":"counter"}}
{"level":"debug","ts":"2022-06-09T12:07:55.738Z","caller":"metrics/debug.go:42","msg":"counter","json":{"name":"atlantis.projects","value":1,"tags":{},"type":"counter"}}
{"level":"debug","ts":"2022-06-09T12:07:55.738Z","caller":"metrics/debug.go:42","msg":"counter","json":{"name":"atlantis.github.pull_is_mergeable.execution_success","value":1,"tags":{},"type":"counter"}}
{"level":"debug","ts":"2022-06-09T12:07:55.738Z","caller":"metrics/debug.go:42","msg":"counter","json":{"name":"atlantis.github.update_status.execution_success","value":2,"tags":{},"type":"counter"}}
{"level":"debug","ts":"2022-06-09T12:07:55.738Z","caller":"metrics/debug.go:42","msg":"counter","json":{"name":"atlantis.cmd.comment.apply.builder.execution_success","value":1,"tags":{},"type":"counter"}}
{"level":"debug","ts":"2022-06-09T12:07:56.169Z","caller":"metrics/debug.go:52","msg":"timer","json":{"name":"atlantis.github.hide_prev_plan_comments.execution_time","value":0.606558535,"tags":{},"type":"timer"}}
{"level":"debug","ts":"2022-06-09T12:07:56.169Z","caller":"vcs/github_client.go:196","msg":"POST /repos/org/repo/issues/2644/comments","json":{}}
{"level":"debug","ts":"2022-06-09T12:07:56.653Z","caller":"server/middleware.go:44","msg":"POST /events – from 10.202.133.71:42634","json":{}}
{"level":"debug","ts":"2022-06-09T12:07:56.653Z","caller":"events/events_controller.go:98","msg":"handling GitHub post","json":{}}
{"level":"debug","ts":"2022-06-09T12:07:56.653Z","caller":"events/events_controller.go:163","msg":"request valid","json":{"gh-request-id":"X-Github-Delivery=cbd206c0-e7ec-11ec-9385-3e7467b3eca5"}}
{"level":"debug","ts":"2022-06-09T12:07:56.654Z","caller":"server/middleware.go:70","msg":"POST /events – respond HTTP 200","json":{}}
{"level":"debug","ts":"2022-06-09T12:07:56.785Z","caller":"events/db_updater.go:25","msg":"updating DB with pull results","json":{"repo":"org/repo","pull":"2644"}}
{"level":"debug","ts":"2022-06-09T12:07:57.127Z","caller":"metrics/debug.go:52","msg":"timer","json":{"name":"atlantis.github.update_status.execution_time","value":0.338338213,"tags":{},"type":"timer"}}
{"level":"debug","ts":"2022-06-09T12:07:57.127Z","caller":"events/post_workflow_hooks_command_runner.go:48","msg":"post-hooks configured, running...","json":{"repo":"org/repo","pull":"2644"}}
{"level":"debug","ts":"2022-06-09T12:07:57.127Z","caller":"events/post_workflow_hooks_command_runner.go:54","msg":"got workspace lock","json":{"repo":"org/repo","pull":"2644"}}
{"level":"info","ts":"2022-06-09T12:07:57.127Z","caller":"events/github_app_working_dir.go:26","msg":"Refreshing git tokens for Github App","json":{"repo":"org/repo","pull":"2644"}}
{"level":"debug","ts":"2022-06-09T12:07:57.127Z","caller":"events/git_cred_writer.go:36","msg":"git credentials file has expected contents, not modifying","json":{"repo":"org/repo","pull":"2644"}}
{"level":"debug","ts":"2022-06-09T12:07:57.127Z","caller":"events/working_dir.go:90","msg":"clone directory \"/atlantis-data/repos/org/repo/2644/default\" already exists, checking if it's at the right commit","json":{"repo":"org/repo","pull":"2644"}}
{"level":"debug","ts":"2022-06-09T12:07:57.130Z","caller":"events/working_dir.go:113","msg":"repo is at correct commit \"ae343891f6b29260d91cbd0462ca065c89572389\" so will not re-clone","json":{"repo":"org/repo","pull":"2644"}}
{"level":"debug","ts":"2022-06-09T12:07:57.218Z","caller":"server/middleware.go:44","msg":"POST /events – from 10.202.137.99:40294","json":{}}
{"level":"debug","ts":"2022-06-09T12:07:57.218Z","caller":"events/events_controller.go:98","msg":"handling GitHub post","json":{}}
{"level":"debug","ts":"2022-06-09T12:07:57.219Z","caller":"events/events_controller.go:163","msg":"request valid","json":{"gh-request-id":"X-Github-Delivery=cc24baa0-e7ec-11ec-9921-267f51e8a77a"}}
{"level":"debug","ts":"2022-06-09T12:07:57.221Z","caller":"server/middleware.go:70","msg":"POST /events – respond HTTP 200","json":{}}
{"level":"debug","ts":"2022-06-09T12:07:57.492Z","caller":"runtime/post_workflow_hook_runner.go:47","msg":"error: exit status 1: running \"infracost comment github --repo $BASE_REPO_OWNER/$BASE_REPO_NAME \\\\\\n
                 --pull-request $PULL_NUM \\\\\\n                          --path /tmp/$BASE_REPO_OWNER-$BASE_REPO_NAME-$PULL_NUM/'*'-infracost.json \\\\\\n                          --github-token $GITHUB_TOKEN \\\\\\n                          --behavior update \\\\\\n                          --policy-path /policies/costs_infracost.rego\\n\" in \"/atlantis-data/repos/org/repo/2644/default\": \n\u001b[91mError:\u001b[0m Error reading JSON file: open /tmp/org-repo-2644/*-infracost.json: no such file or directory\n\n\u001b[33mUpdate:\u001b[0m A new version of Infracost is available: \u001b[96mv0.9.24\u001b[0m → \u001b[96mv0.10.2\u001b[0m\n  $ curl -fsSL https://raw.githubusercontent.com/infracost/infracost/master/scripts/install.sh | sh\n","json":{"repo":"org/repo","pull":"2644"}}
{"level":"error","ts":"2022-06-09T12:07:57.493Z","caller":"events/command_runner.go:282","msg":"Error running post-workflow hooks exit status 1: running \"infracost comment github --repo $BASE_REPO_OWNER/$BASE_REPO_NAME \\\\\\n                          --pull-request $PULL_NUM \\\\\\n                          --path /tmp/$BASE_REPO_OWNER-$BASE_REPO_NAME-$PULL_NUM/'*'-infracost.json \\\\\\n                          --github-token $GITHUB_TOKEN \\\\\\n                          --behavior update \\\\\\n                          --policy-path /policies/costs_infracost.rego\\n\" in \"/atlantis-data/repos/org/repo/2644/default\": \n\u001b[91mError:\u001b[0m Error reading JSON file: open /tmp/org-repo-2644/*-infracost.json: no such file or directory\n\n\u001b[33mUpdate:\u001b[0m A new version of Infracost is available: \u001b[96mv0.9.24\u001b[0m → \u001b[96mv0.10.2\u001b[0m\n  $ curl -fsSL https://raw.githubusercontent.com/infracost/infracost/master/scripts/install.sh | sh\n.","json":{"repo":"org/repo","pull":"2644"},"stacktrace":"github.com/runatlantis/atlantis/server/events.(*DefaultCommandRunner).RunCommentCommand\n\tgithub.com/runatlantis/atlantis/server/events/command_runner.go:282"}
{"level":"debug","ts":"2022-06-09T12:07:57.493Z","caller":"metrics/debug.go:52","msg":"timer","json":{"name":"atlantis.cmd.comment.apply.execution_time","value":12.772141684,"tags":{},"type":"timer"}}
{"level":"debug","ts":"2022-06-09T12:07:57.738Z","caller":"metrics/debug.go:42","msg":"counter","json":{"name":"atlantis.github.create_comment.execution_success","value":1,"tags":{},"type":"counter"}}
{"level":"debug","ts":"2022-06-09T12:07:57.738Z","caller":"metrics/debug.go:42","msg":"counter","json":{"name":"atlantis.github.update_status.execution_success","value":1,"tags":{},"type":"counter"}}
{"level":"debug","ts":"2022-06-09T12:07:57.738Z","caller":"metrics/debug.go:42","msg":"counter","json":{"name":"atlantis.github.event.comment.created.success_200","value":1,"tags":{},"type":"counter"}}
```

</details>

PR status after apply failed:

```
$ gh api  repos/org/repo/pulls/2644 | jq | grep -e state -e merge -e lock
  "state": "open",
  "locked": false,
  "merged_at": null,
  "auto_merge": null,
  "active_lock_reason": null,
  "merged": false,
  "mergeable": true,
  "mergeable_state": "unstable",
  "merged_by": null,
```

PR checks after apply failed (everything was green before, without apply checks existing):

```
$ gh pr checks https://github.com/org/repo/pull/2644
Some checks were not successful
2 failing, 7 successful, 0 skipped, and 0 pending checks

X  atlantis/apply
X  atlantis/apply: environment/default
✓  GitHub Bot
✓  Sanity Check
✓  atlantis/plan
✓  atlantis/plan: environment/default
✓  atlantis/policy_check
```

### Environment details

- Atlantis version: 0.19.4
- Atlantis flags: `--write-git-creds --repo-allowlist=github.com/org/repo --repo-config=/repos.yaml --enable-policy-checks=true --hide-prev-plan-comments`

Atlantis server-side config file:

```
repos:
  - id: /.*/
    branch: /.*/
    apply_requirements: [approved, mergeable]
    workflow: default
    allowed_workflows: [default]
    allow_custom_workflows: false
    delete_source_branch_on_merge: false

    pre_workflow_hooks:
      # Clean up any files left over from previous runs
      - run: rm -rf /tmp/$BASE_REPO_OWNER-$BASE_REPO_NAME-$PULL_NUM
      - run: mkdir -p /tmp/$BASE_REPO_OWNER-$BASE_REPO_NAME-$PULL_NUM
      - run: some_command

    post_workflow_hooks:
      - run: |
          infracost comment github --repo $BASE_REPO_OWNER/$BASE_REPO_NAME \
                                    --pull-request $PULL_NUM \
                                    --path /tmp/$BASE_REPO_OWNER-$BASE_REPO_NAME-$PULL_NUM/'*'-infracost.json \
                                    --github-token $GITHUB_TOKEN \
                                    --behavior update \
                                    --policy-path /policies/costs_infracost.rego
      - run: rm -rf /tmp/$BASE_REPO_OWNER-$BASE_REPO_NAME-$PULL_NUM

workflows:
  default:
    plan:
      steps:
        - env:
            name: ATLANTIS_TERRAFORM_VERSION
            command: /scripts/get-tf-version
        - env:
            name: INFRACOST_OUTPUT
            command: 'echo "/tmp/$BASE_REPO_OWNER-$BASE_REPO_NAME-$PULL_NUM/$WORKSPACE-${REPO_REL_DIR//\//-}-infracost.json"'
        - run: terraform${ATLANTIS_TERRAFORM_VERSION} init -input=false -no-color > /dev/null
        - run: test -n "$WORKSPACE" && terraform${ATLANTIS_TERRAFORM_VERSION} workspace select -no-color $WORKSPACE
        - run: terraform${ATLANTIS_TERRAFORM_VERSION} plan -input=false -refresh -no-color -out $PLANFILE
        - run: terraform${ATLANTIS_TERRAFORM_VERSION} show -json $PLANFILE > $SHOWFILE
        - run: infracost breakdown --path=$SHOWFILE --format=json --log-level=warn --out-file=$INFRACOST_OUTPUT

    policy_check:
      steps:
        - env:
            name: INFRACOST_OUTPUT
            command: 'echo "/tmp/$BASE_REPO_OWNER-$BASE_REPO_NAME-$PULL_NUM/$WORKSPACE-${REPO_REL_DIR//\//-}-infracost.json"'
        - run: ( set -o pipefail; conftest test --no-color --output json -p /policies/costs_conftest.rego --namespace infracost $INFRACOST_OUTPUT | jq -M )

    apply:
      steps:
        - run: /scripts/ensure-apply-permission
        - env:
            name: ATLANTIS_TERRAFORM_VERSION
            command: /scripts/get-tf-version
        - run: test -f $WORKSPACE.auto.tfvars.json && sops -d -i $WORKSPACE.auto.tfvars.json || true
        - run: ( set -o pipefail; terraform${ATLANTIS_TERRAFORM_VERSION} apply -no-color $PLANFILE | grep -v 'Refreshing state...' )

policies:
  owners:
    users:
      - some_user
  policy_sets:
    - name: infracost
      path: /policies/costs_conftest.rego
      source: local
```

### Additional Context

* We updated to 0.19.x to use policy checks. Works fine with 0.18.x and policy checks disabled.
* Keeping using 0.19.4 and removing all policy check configuration also makes apply fail.
* Reverting to 0.19.2 without policy_check stage also works.


Discussion / hints:

Fix patch:
diff --git a/server/events/vcs/github_client.go b/server/events/vcs/github_client.go
index d3615ad172..74e56b3048 100644
--- a/server/events/vcs/github_client.go
+++ b/server/events/vcs/github_client.go
@@ -25,6 +25,7 @@ import (
 	"github.com/google/go-github/v31/github"
 	"github.com/pkg/errors"
 	"github.com/runatlantis/atlantis/server/core/config"
+	"github.com/runatlantis/atlantis/server/events/command"
 	"github.com/runatlantis/atlantis/server/events/models"
 	"github.com/runatlantis/atlantis/server/events/vcs/common"
 	"github.com/runatlantis/atlantis/server/logging"
@@ -303,6 +304,7 @@ func (g *GithubClient) PullIsMergeable(repo models.Repo, pull models.PullRequest
 		return false, errors.Wrap(err, "getting pull request")
 	}
 	state := githubPR.GetMergeableState()
+	g.logger.Debug("PR mergeable state is %v", state)
 	// We map our mergeable check to when the GitHub merge button is clickable.
 	// This corresponds to the following states:
 	// clean: No conflicts, all requirements satisfied.
@@ -311,7 +313,48 @@ func (g *GithubClient) PullIsMergeable(repo models.Repo, pull models.PullRequest
 	//           status checks. Merging is allowed (yellow box).
 	// has_hooks: GitHub Enterprise only, if a repo has custom pre-receive
 	//            hooks. Merging is allowed (green box).
+	// blocked: Blocked by a failing/missing required status check.
 	// See: https://github.com/octokit/octokit.net/issues/1763
+	if state == "blocked" {
+		var allStatuses []*github.RepoStatus
+		nextPage := 0
+		for {
+			g.logger.Debug("GET /repos/%v/%v/commits/%d/status", repo.Owner, repo.Name, pull.HeadBranch)
+			combinedStatus, resp, err := g.client.Repositories.GetCombinedStatus(g.ctx, repo.Owner, repo.Name, pull.HeadBranch, &github.ListOptions{
+				Page: nextPage,
+			})
+			if err != nil {
+				return false, errors.Wrap(err, "fetching PR statuses")
+			}
+			allStatuses = append(allStatuses, combinedStatus.Statuses...)
+			if resp.NextPage == 0 {
+				break
+			}
+			nextPage = resp.NextPage
+		}
+		g.logger.Debug("GET /repos/%v/%v/branches/%d/protection/required_status_checks", repo.Owner, repo.Name, pull.BaseBranch)
+		requiredChecks, _, err := g.client.Repositories.GetRequiredStatusChecks(g.ctx, repo.Owner, repo.Name, pull.BaseBranch)
+		if err != nil {
+			return false, errors.Wrap(err, "fetching PR required checks")
+		}
+		for _, status := range allStatuses {
+			for _, requiredCheck := range requiredChecks.Contexts {
+				// Ignore any commit statuses with 'altantis/apply' as prefix
+				if strings.HasPrefix(status.GetContext(), fmt.Sprintf("atlantis/%s", command.Apply.String())) {
+					continue
+				}
+				if status.GetContext() == requiredCheck {
+					if status.GetState() == "failure" || status.GetState() == "pending" {
+						g.logger.Debug("Failed check %v", requiredCheck)
+						return false, nil
+					}
+				}
+			}
+		}
+		g.logger.Debug("Blocked only by atlantis/apply")
+		return true, nil
+
+	}
 	if state != "clean" && state != "unstable" && state != "has_hooks" {
 		return false, nil
 	}


Test patch:
diff --git a/server/events/vcs/github_client_test.go b/server/events/vcs/github_client_test.go
index 42583f70fc..72f887f678 100644
--- a/server/events/vcs/github_client_test.go
+++ b/server/events/vcs/github_client_test.go
@@ -476,59 +476,102 @@ func TestGithubClient_PullIsApproved(t *testing.T) {
 
 func TestGithubClient_PullIsMergeable(t *testing.T) {
 	cases := []struct {
-		state        string
-		expMergeable bool
+		state               string
+		requiredCheckName   string
+		requiredCheckStatus string
+		expMergeable        bool
 	}{
 		{
 			"dirty",
+			"",
+			"",
 			false,
 		},
 		{
 			"unknown",
-			false,
-		},
-		{
-			"blocked",
+			"",
+			"",
 			false,
 		},
 		{
 			"behind",
+			"",
+			"",
 			false,
 		},
 		{
 			"random",
+			"",
+			"",
 			false,
 		},
 		{
 			"unstable",
+			"",
+			"",
 			true,
 		},
 		{
 			"has_hooks",
+			"",
+			"",
 			true,
 		},
 		{
 			"clean",
+			"",
+			"",
 			true,
 		},
 		{
+			"",
+			"",
 			"",
 			false,
 		},
+		{
+			"blocked",
+			"atlantis/apply",
+			"failure",
+			true,
+		},
+		{
+			"blocked",
+			"atlantis/apply",
+			"pending",
+			true,
+		},
+		{
+			"blocked",
+			"required_check",
+			"failure",
+			false,
+		},
 	}
 
 	// Use a real GitHub json response and edit the mergeable_state field.
 	jsBytes, err := os.ReadFile("fixtures/github-pull-request.json")
 	Ok(t, err)
-	json := string(jsBytes)
+	prJSON := string(jsBytes)
 
 	for _, c := range cases {
 		t.Run(c.state, func(t *testing.T) {
-			response := strings.Replace(json,
+			response := strings.Replace(prJSON,
 				`"mergeable_state": "clean"`,
 				fmt.Sprintf(`"mergeable_state": "%s"`, c.state),
 				1,
 			)
+			responseStatus, _ := json.Marshal(map[string][]map[string]string{
+				"statuses": {{
+					"context": c.requiredCheckName,
+					"state":   c.requiredCheckStatus,
+				}},
+			})
+			responseRequiredChecks, _ := json.Marshal(map[string][]string{
+				"contexts": {
+					c.requiredCheckName,
+				},
+			})
 
 			testServer := httptest.NewTLSServer(
 				http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@@ -536,6 +579,12 @@ func TestGithubClient_PullIsMergeable(t *testing.T) {
 					case "/api/v3/repos/owner/repo/pulls/1":
 						w.Write([]byte(response)) // nolint: errcheck
 						return
+					case "/api/v3/repos/owner/repo/commits/headBranch/status":
+						w.Write(responseStatus) // nolint: errcheck
+						return
+					case "/api/v3/repos/owner/repo/branches/baseBranch/protection/required_status_checks":
+						w.Write(responseRequiredChecks) // nolint: errcheck
+						return
 					default:
 						t.Errorf("got unexpected request at %q", r.RequestURI)
 						http.Error(w, "not found", http.StatusNotFound)
@@ -559,7 +608,9 @@ func TestGithubClient_PullIsMergeable(t *testing.T) {
 					Hostname: "github.com",
 				},
 			}, models.PullRequest{
-				Num: 1,
+				Num:        1,
+				HeadBranch: "headBranch",
+				BaseBranch: "baseBranch",
 			})
 			Ok(t, err)
 			Equals(t, c.expMergeable, actMergeable)