mirror of
https://github.com/go-gitea/gitea.git
synced 2026-08-10 08:43:58 +00:00
fix(workflows): branch protection status checks fail when workflow uses on: paths filter (#38237)
This commit is contained in:
@@ -344,6 +344,59 @@ jobs:
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Filtered required scoped check passes as skipped and allows merge", func(t *testing.T) {
|
||||
// A required scoped workflow excluded by a paths filter posts a skipped (success) commit status,
|
||||
// so the required check is satisfied and the PR can merge.
|
||||
|
||||
const scopedFilteredPRWorkflow = `name: Scoped Filtered PR
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- src/**
|
||||
jobs:
|
||||
scoped-filtered-job:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: echo scoped-filtered
|
||||
`
|
||||
source := createTestRepo(t, "sw-filtered-source", false)
|
||||
createRepoWorkflowFile(t, user2, user2Token, source, ".gitea/scoped_workflows/pr.yaml", scopedFilteredPRWorkflow)
|
||||
registerUserScopedSource(t, source, "pr.yaml") // required
|
||||
|
||||
consumer := createTestRepo(t, "sw-filtered-consumer", false)
|
||||
// Protect the default branch (its own status check stays off, so only the required scoped check gates the merge).
|
||||
user2Session.MakeRequest(t, NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/settings/branches/edit", consumer.OwnerName, consumer.Name), map[string]string{
|
||||
"rule_name": consumer.DefaultBranch,
|
||||
"enable_push": "true",
|
||||
"block_admin_merge_override": "true", // otherwise the repo owner bypasses the status check
|
||||
}), http.StatusSeeOther)
|
||||
|
||||
// Open a PR that changes a file NOT matching the workflow's `paths: [src/**]`, so it is filtered out.
|
||||
prFile := &api.CreateFileOptions{
|
||||
FileOptions: api.FileOptions{
|
||||
BranchName: consumer.DefaultBranch, NewBranchName: "filtered-pr", Message: "pr change",
|
||||
Author: api.Identity{Name: user2.Name, Email: user2.Email},
|
||||
Committer: api.Identity{Name: user2.Name, Email: user2.Email},
|
||||
Dates: api.CommitDateOptions{Author: time.Now(), Committer: time.Now()},
|
||||
},
|
||||
ContentBase64: base64.StdEncoding.EncodeToString([]byte("pr change")),
|
||||
}
|
||||
createWorkflowFile(t, user2Token, consumer.OwnerName, consumer.Name, "docs.txt", prFile)
|
||||
apiCtx := NewAPITestContext(t, user2.Name, consumer.Name, auth_model.AccessTokenScopeWriteRepository)
|
||||
pr, err := doAPICreatePullRequest(apiCtx, consumer.OwnerName, consumer.Name, consumer.DefaultBranch, "filtered-pr")(t)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Filtered: no scoped run is created, but a skipped commit status is posted on the PR head.
|
||||
assert.Equal(t, 0, unittest.GetCount(t, &actions_model.ActionRun{RepoID: consumer.ID, IsScopedRun: true}), "filtered scoped workflow creates no run")
|
||||
assertSkippedCommitStatusExists(t, consumer.ID, pr.Head.Sha, "pull_request")
|
||||
|
||||
// The skipped (success) status satisfies the required scoped check (prefixed with the source repo), so the merge is allowed.
|
||||
assert.NoError(t, queue.GetManager().FlushAll(t.Context(), 5*time.Second))
|
||||
mergeReq := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/merge", consumer.OwnerName, consumer.Name, pr.Index),
|
||||
&forms.MergePullRequestForm{Do: string(repo_model.MergeStyleMerge), MergeMessageField: "merge"}).AddTokenAuth(user2Token)
|
||||
user2Session.MakeRequest(t, mergeReq, http.StatusOK)
|
||||
})
|
||||
|
||||
t.Run("Settings page required patterns", func(t *testing.T) {
|
||||
source := createTestRepo(t, "sw-settings-source", false)
|
||||
createRepoWorkflowFile(t, user2, user2Token, source, ".gitea/scoped_workflows/push.yaml", scopedPushWorkflow)
|
||||
|
||||
@@ -215,8 +215,9 @@ jobs:
|
||||
err = pull_service.NewPullRequest(t.Context(), prOpts)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// the new pull request cannot trigger actions, so there is still only 1 record
|
||||
// the new pull request is filtered by paths, so no run is created; a skipped commit status is posted instead
|
||||
assert.Equal(t, 1, unittest.GetCount(t, &actions_model.ActionRun{RepoID: baseRepo.ID}))
|
||||
assertSkippedCommitStatusExists(t, baseRepo.ID, addFileToForkedResp.Commit.SHA, "pull_request_target")
|
||||
})
|
||||
}
|
||||
|
||||
@@ -338,6 +339,9 @@ jobs:
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, addFileToBranchResp)
|
||||
// the push to test-skip-ci is filtered by branches, so no run is created; a skipped commit status is posted instead
|
||||
assert.Equal(t, 1, unittest.GetCount(t, &actions_model.ActionRun{RepoID: repo.ID}))
|
||||
assertSkippedCommitStatusExists(t, repo.ID, addFileToBranchResp.Commit.SHA, "push")
|
||||
|
||||
resp := testPullCreate(t, session, "user2", "skip-ci", true, "master", "test-skip-ci", "[skip ci] test-skip-ci")
|
||||
|
||||
@@ -345,7 +349,7 @@ jobs:
|
||||
url := test.RedirectURL(resp)
|
||||
assert.Regexp(t, "^/user2/skip-ci/pulls/[0-9]*$", url)
|
||||
|
||||
// the pr title contains a configured skip-ci string, so there is still only 1 record
|
||||
// the pr title contains a configured skip-ci string, so no run and no skipped status are created
|
||||
assert.Equal(t, 1, unittest.GetCount(t, &actions_model.ActionRun{RepoID: repo.ID}))
|
||||
})
|
||||
}
|
||||
@@ -1879,3 +1883,16 @@ jobs:
|
||||
runner.fetchNoTask(t)
|
||||
})
|
||||
}
|
||||
|
||||
// assertSkippedCommitStatusExists asserts that a filtered-out workflow posted a skipped commit status on sha
|
||||
func assertSkippedCommitStatusExists(t *testing.T, repoID int64, sha, eventSuffix string) {
|
||||
t.Helper()
|
||||
statuses, err := git_model.GetLatestCommitStatus(t.Context(), repoID, sha, db.ListOptionsAll)
|
||||
require.NoError(t, err)
|
||||
for _, s := range statuses {
|
||||
if s.State == commitstatus.CommitStatusSkipped && strings.Contains(s.Context, "("+eventSuffix+")") {
|
||||
return
|
||||
}
|
||||
}
|
||||
assert.Failf(t, "missing skipped commit status", "no skipped commit status with event %q on %s (found %d statuses)", eventSuffix, sha, len(statuses))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user