diff --git a/server/events/vcs/github_client.go b/server/events/vcs/github_client.go index c1ce13581d..f9036e7b53 100644 --- a/server/events/vcs/github_client.go +++ b/server/events/vcs/github_client.go @@ -481,6 +481,7 @@ type WorkflowRun struct { RepositoryFileUrl githubv4.String RepositoryName githubv4.String } + RunNumber githubv4.Int } type CheckRun struct { @@ -718,10 +719,27 @@ func StatusContextPassed(statusContext StatusContext, vcsstatusname string) bool } func ExpectedCheckPassed(expectedContext githubv4.String, checkRuns []CheckRun, statusContexts []StatusContext, vcsstatusname string) bool { + // If there's no WorkflowRun, we assume there's only one CheckRun with the given name. + // In this case, we evaluate and return the status of this CheckRun. + // If there is WorkflowRun, we assume there can be multiple checkRuns with the given name, + // so we retrieve the latest checkRun and evaluate and return the status of the latest CheckRun. + latestCheckRunNumber := githubv4.Int(-1) + var latestCheckRun *CheckRun for _, checkRun := range checkRuns { - if checkRun.Name == expectedContext { + if checkRun.Name != expectedContext { + continue + } + if checkRun.CheckSuite.WorkflowRun == nil { return CheckRunPassed(checkRun) } + if checkRun.CheckSuite.WorkflowRun.RunNumber > latestCheckRunNumber { + latestCheckRunNumber = checkRun.CheckSuite.WorkflowRun.RunNumber + latestCheckRun = &checkRun + } + } + + if latestCheckRun != nil { + return CheckRunPassed(*latestCheckRun) } for _, statusContext := range statusContexts { @@ -734,6 +752,11 @@ func ExpectedCheckPassed(expectedContext githubv4.String, checkRuns []CheckRun, } func (g *GithubClient) ExpectedWorkflowPassed(expectedWorkflow WorkflowFileReference, checkRuns []CheckRun) (bool, error) { + // If there's no WorkflowRun, we just skip evaluation for given CheckRun. + // If there is WorkflowRun, we assume there can be multiple checkRuns with the given name, + // so we retrieve the latest checkRun and evaluate and return the status of the latest CheckRun. + latestCheckRunNumber := githubv4.Int(-1) + var latestCheckRun *CheckRun for _, checkRun := range checkRuns { if checkRun.CheckSuite.WorkflowRun == nil { continue @@ -743,10 +766,17 @@ func (g *GithubClient) ExpectedWorkflowPassed(expectedWorkflow WorkflowFileRefer return false, err } if match { - return CheckRunPassed(checkRun), nil + if checkRun.CheckSuite.WorkflowRun.RunNumber > latestCheckRunNumber { + latestCheckRunNumber = checkRun.CheckSuite.WorkflowRun.RunNumber + latestCheckRun = &checkRun + } } } + if latestCheckRun != nil { + return CheckRunPassed(*latestCheckRun), nil + } + return false, nil } diff --git a/server/events/vcs/github_client_test.go b/server/events/vcs/github_client_test.go index 81ec7ee7a4..ffd0e02e59 100644 --- a/server/events/vcs/github_client_test.go +++ b/server/events/vcs/github_client_test.go @@ -800,6 +800,12 @@ func TestGithubClient_PullIsMergeableWithAllowMergeableBypassApply(t *testing.T) `"APPROVED"`, true, }, + { + "blocked", + "ruleset-workflow-passed-multiple-runs.json", + `"APPROVED"`, + true, + }, { "blocked", "ruleset-workflow-passed-sha-match.json", diff --git a/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-evaluate-workflow-failed.json b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-evaluate-workflow-failed.json index ddde1d8ac5..3fe4178f65 100644 --- a/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-evaluate-workflow-failed.json +++ b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-evaluate-workflow-failed.json @@ -78,7 +78,8 @@ "path": ".github/workflows/my-required-workflow.yaml", "repositoryFileUrl": "https://github.com/runatlantis/atlantis/blob/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/.github/workflows/my-required-workflow.yaml", "repositoryName": "runatlantis/atlantis" - } + }, + "runNumber": 1 } } } @@ -92,4 +93,4 @@ } } } -} \ No newline at end of file +} diff --git a/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-workflow-failed.json b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-workflow-failed.json index 570fdb9276..3286ca50e3 100644 --- a/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-workflow-failed.json +++ b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-workflow-failed.json @@ -78,7 +78,8 @@ "path": ".github/workflows/my-required-workflow.yaml", "repositoryFileUrl": "https://github.com/runatlantis/atlantis/blob/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/.github/workflows/my-required-workflow.yaml", "repositoryName": "runatlantis/atlantis" - } + }, + "runNumber": 1 } } } @@ -92,4 +93,4 @@ } } } -} \ No newline at end of file +} diff --git a/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-workflow-passed-multiple-runs.json b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-workflow-passed-multiple-runs.json new file mode 100644 index 0000000000..50fe3cd2b0 --- /dev/null +++ b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-workflow-passed-multiple-runs.json @@ -0,0 +1,112 @@ +{ + "data": { + "repository": { + "pullRequest": { + "reviewDecision": null, + "baseRef": { + "branchProtectionRule": { + "requiredStatusChecks": [] + }, + "rules": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "type": "REQUIRED_STATUS_CHECKS", + "repositoryRuleset": { + "enforcement": "ACTIVE" + }, + "parameters": { + "requiredStatusChecks": [ + { + "context": "atlantis/apply" + } + ] + } + }, + { + "type": "WORKFLOWS", + "repositoryRuleset": { + "enforcement": "ACTIVE" + }, + "parameters": { + "workflows": [ + { + "path": ".github/workflows/my-required-workflow.yaml", + "repositoryId": 120519269, + "sha": null + } + ] + } + } + ] + } + }, + "commits": { + "nodes": [ + { + "commit": { + "statusCheckRollup": { + "contexts": { + "pageInfo": { + "endCursor": "QWERTY", + "hasNextPage": false + }, + "nodes": [ + { + "__typename": "StatusContext", + "context": "atlantis/apply", + "state": "PENDING", + "isRequired": true + }, + { + "__typename": "StatusContext", + "context": "atlantis/plan", + "state": "SUCCESS", + "isRequired": false + }, + { + "__typename": "CheckRun", + "name": "my required check", + "conclusion": "FAILURE", + "isRequired": true, + "checkSuite": { + "workflowRun": { + "file": { + "path": ".github/workflows/my-required-workflow.yaml", + "repositoryFileUrl": "https://github.com/runatlantis/atlantis/blob/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/.github/workflows/my-required-workflow.yaml", + "repositoryName": "runatlantis/atlantis" + }, + "runNumber": 1 + } + } + }, + { + "__typename": "CheckRun", + "name": "my required check", + "conclusion": "SUCCESS", + "isRequired": true, + "checkSuite": { + "workflowRun": { + "file": { + "path": ".github/workflows/my-required-workflow.yaml", + "repositoryFileUrl": "https://github.com/runatlantis/atlantis/blob/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/.github/workflows/my-required-workflow.yaml", + "repositoryName": "runatlantis/atlantis" + }, + "runNumber": 2 + } + } + } + ] + } + } + } + } + ] + } + } + } + } +} diff --git a/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-workflow-passed-sha-match.json b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-workflow-passed-sha-match.json index e40b014ab3..cb7d45432c 100644 --- a/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-workflow-passed-sha-match.json +++ b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-workflow-passed-sha-match.json @@ -78,7 +78,8 @@ "path": ".github/workflows/my-required-workflow.yaml", "repositoryFileUrl": "https://github.com/runatlantis/atlantis/blob/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/.github/workflows/my-required-workflow.yaml", "repositoryName": "runatlantis/atlantis" - } + }, + "runNumber": 1 } } } @@ -92,4 +93,4 @@ } } } -} \ No newline at end of file +} diff --git a/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-workflow-passed-sha-mismatch.json b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-workflow-passed-sha-mismatch.json index 5a79ce3e33..228a66e430 100644 --- a/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-workflow-passed-sha-mismatch.json +++ b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-workflow-passed-sha-mismatch.json @@ -78,7 +78,8 @@ "path": ".github/workflows/my-required-workflow.yaml", "repositoryFileUrl": "https://github.com/runatlantis/atlantis/blob/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/.github/workflows/my-required-workflow.yaml", "repositoryName": "runatlantis/atlantis" - } + }, + "runNumber": 1 } } } @@ -92,4 +93,4 @@ } } } -} \ No newline at end of file +} diff --git a/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-workflow-passed.json b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-workflow-passed.json index 6a88b4c8c5..8c964922d9 100644 --- a/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-workflow-passed.json +++ b/server/events/vcs/testdata/github-pull-request-mergeability/ruleset-workflow-passed.json @@ -78,7 +78,8 @@ "path": ".github/workflows/my-required-workflow.yaml", "repositoryFileUrl": "https://github.com/runatlantis/atlantis/blob/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/.github/workflows/my-required-workflow.yaml", "repositoryName": "runatlantis/atlantis" - } + }, + "runNumber": 1 } } } @@ -92,4 +93,4 @@ } } } -} \ No newline at end of file +}