chore: initialize Gitea v1.27.2 fork
giteabot backport / giteabot (push) Canceled after 0s
giteabot / giteabot (push) Canceled after 0s
release-nightly / nightly-binary (push) Canceled after 0s
release-nightly / nightly-container (push) Canceled after 0s
cache-seeder / gobuild (push) Canceled after 0s
cache-seeder / lint (bindata, lint-backend) (push) Canceled after 0s
release-nightly-snapcraft / build-and-publish (push) Canceled after 0s
giteabot backport / giteabot (push) Canceled after 0s
giteabot / giteabot (push) Canceled after 0s
release-nightly / nightly-binary (push) Canceled after 0s
release-nightly / nightly-container (push) Canceled after 0s
cache-seeder / gobuild (push) Canceled after 0s
cache-seeder / lint (bindata, lint-backend) (push) Canceled after 0s
release-nightly-snapcraft / build-and-publish (push) Canceled after 0s
Includes direct password setup links in registration emails. Assisted-by: Codex:GPT-5
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
// Copyright 2024 The Gitea Authors.
|
||||
// All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package pull
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
actions_model "gitea.dev/models/actions"
|
||||
"gitea.dev/models/db"
|
||||
git_model "gitea.dev/models/git"
|
||||
repo_model "gitea.dev/models/repo"
|
||||
"gitea.dev/models/unittest"
|
||||
"gitea.dev/modules/commitstatus"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestMergeRequiredContextsCommitStatus(t *testing.T) {
|
||||
cases := []struct {
|
||||
commitStatuses []*git_model.CommitStatus
|
||||
requiredContexts []string
|
||||
expected commitstatus.CommitStatusState
|
||||
}{
|
||||
{
|
||||
commitStatuses: []*git_model.CommitStatus{},
|
||||
requiredContexts: []string{},
|
||||
expected: commitstatus.CommitStatusPending,
|
||||
},
|
||||
{
|
||||
commitStatuses: []*git_model.CommitStatus{
|
||||
{Context: "Build xxx", State: commitstatus.CommitStatusSkipped},
|
||||
},
|
||||
requiredContexts: []string{"Build*"},
|
||||
expected: commitstatus.CommitStatusSuccess,
|
||||
},
|
||||
{
|
||||
commitStatuses: []*git_model.CommitStatus{
|
||||
{Context: "Build 1", State: commitstatus.CommitStatusSkipped},
|
||||
{Context: "Build 2", State: commitstatus.CommitStatusSuccess},
|
||||
{Context: "Build 3", State: commitstatus.CommitStatusSuccess},
|
||||
},
|
||||
requiredContexts: []string{"Build*"},
|
||||
expected: commitstatus.CommitStatusSuccess,
|
||||
},
|
||||
{
|
||||
commitStatuses: []*git_model.CommitStatus{
|
||||
{Context: "Build 1", State: commitstatus.CommitStatusSuccess},
|
||||
{Context: "Build 2", State: commitstatus.CommitStatusSuccess},
|
||||
{Context: "Build 2t", State: commitstatus.CommitStatusPending},
|
||||
},
|
||||
requiredContexts: []string{"Build*", "Build 2t*"},
|
||||
expected: commitstatus.CommitStatusPending,
|
||||
},
|
||||
{
|
||||
commitStatuses: []*git_model.CommitStatus{
|
||||
{Context: "Build 1", State: commitstatus.CommitStatusSuccess},
|
||||
{Context: "Build 2", State: commitstatus.CommitStatusSuccess},
|
||||
{Context: "Build 2t", State: commitstatus.CommitStatusFailure},
|
||||
},
|
||||
requiredContexts: []string{"Build*", "Build 2t*"},
|
||||
expected: commitstatus.CommitStatusFailure,
|
||||
},
|
||||
{
|
||||
commitStatuses: []*git_model.CommitStatus{
|
||||
{Context: "Build 1", State: commitstatus.CommitStatusSuccess},
|
||||
{Context: "Build 2", State: commitstatus.CommitStatusSuccess},
|
||||
{Context: "Build 2t", State: commitstatus.CommitStatusFailure},
|
||||
},
|
||||
requiredContexts: []string{"Build*"},
|
||||
expected: commitstatus.CommitStatusFailure,
|
||||
},
|
||||
{
|
||||
commitStatuses: []*git_model.CommitStatus{
|
||||
{Context: "Build 1", State: commitstatus.CommitStatusSuccess},
|
||||
{Context: "Build 2", State: commitstatus.CommitStatusSuccess},
|
||||
{Context: "Build 2t", State: commitstatus.CommitStatusSuccess},
|
||||
},
|
||||
requiredContexts: []string{"Build*", "Build 2t*", "Build 3*"},
|
||||
expected: commitstatus.CommitStatusPending,
|
||||
},
|
||||
{
|
||||
commitStatuses: []*git_model.CommitStatus{
|
||||
{Context: "Build 1", State: commitstatus.CommitStatusSuccess},
|
||||
{Context: "Build 2", State: commitstatus.CommitStatusSuccess},
|
||||
{Context: "Build 2t", State: commitstatus.CommitStatusSuccess},
|
||||
},
|
||||
requiredContexts: []string{"Build*", "Build *", "Build 2t*", "Build 1*"},
|
||||
expected: commitstatus.CommitStatusSuccess,
|
||||
},
|
||||
}
|
||||
for i, c := range cases {
|
||||
assert.Equal(t, c.expected, MergeRequiredContextsCommitStatus(c.commitStatuses, c.requiredContexts), "case %d", i)
|
||||
}
|
||||
}
|
||||
|
||||
// TestEffectiveRequiredContexts: every required scoped workflow's stored status-check patterns are appended to the
|
||||
// branch protection's configured contexts unconditionally (must-present; the matching is done downstream).
|
||||
func TestEffectiveRequiredContexts(t *testing.T) {
|
||||
require.NoError(t, unittest.PrepareTestDatabase())
|
||||
consumer := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}) // owned by user5
|
||||
pbOn := &git_model.ProtectedBranch{EnableStatusCheck: true, StatusCheckContexts: []string{"configured/check"}}
|
||||
|
||||
t.Run("nil protected branch: nil", func(t *testing.T) {
|
||||
got, err := EffectiveRequiredContexts(t.Context(), consumer, nil)
|
||||
require.NoError(t, err)
|
||||
assert.Nil(t, got)
|
||||
})
|
||||
|
||||
t.Run("status checks disabled, no required scoped: nothing required", func(t *testing.T) {
|
||||
pbOff := &git_model.ProtectedBranch{EnableStatusCheck: false, StatusCheckContexts: []string{"configured/check"}}
|
||||
got, err := EffectiveRequiredContexts(t.Context(), consumer, pbOff)
|
||||
require.NoError(t, err)
|
||||
assert.Empty(t, got) // the rule's own status check is off and no required scoped workflow applies -> nothing gates
|
||||
})
|
||||
|
||||
t.Run("owner with no scoped sources: configured contexts unchanged", func(t *testing.T) {
|
||||
noSourceRepo := &repo_model.Repository{ID: consumer.ID, OwnerID: 99999}
|
||||
got, err := EffectiveRequiredContexts(t.Context(), noSourceRepo, pbOn)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []string{"configured/check"}, got)
|
||||
})
|
||||
|
||||
t.Run("required workflow patterns appended", func(t *testing.T) {
|
||||
require.NoError(t, db.Insert(t.Context(), &actions_model.ActionScopedWorkflowSource{
|
||||
OwnerID: consumer.OwnerID,
|
||||
SourceRepoID: 1,
|
||||
WorkflowConfigs: map[string]*actions_model.ScopedWorkflowConfig{
|
||||
"ci.yaml": {Required: true, Patterns: []string{"org/src: ci.yaml / build (pull_request)", "org/src: ci.yaml / lint (pull_request)"}},
|
||||
"old.yaml": {Required: false, Patterns: []string{"org/src: old.yaml / *"}}, // kept as history, must NOT be enforced
|
||||
},
|
||||
}))
|
||||
// No status is passed/needed: required patterns are enforced even though nothing has posted them yet (must-present).
|
||||
got, err := EffectiveRequiredContexts(t.Context(), consumer, pbOn)
|
||||
require.NoError(t, err)
|
||||
assert.ElementsMatch(t, []string{
|
||||
"configured/check",
|
||||
"org/src: ci.yaml / build (pull_request)",
|
||||
"org/src: ci.yaml / lint (pull_request)",
|
||||
}, got)
|
||||
assert.NotContains(t, got, "org/src: old.yaml / *", "a non-required (history) config must not be enforced")
|
||||
})
|
||||
|
||||
t.Run("status checks disabled, with required scoped: only the scoped patterns gate", func(t *testing.T) {
|
||||
pbOff := &git_model.ProtectedBranch{EnableStatusCheck: false, StatusCheckContexts: []string{"configured/check"}}
|
||||
got, err := EffectiveRequiredContexts(t.Context(), consumer, pbOff)
|
||||
require.NoError(t, err)
|
||||
// "configured/check" is dropped (the rule's own status check is off); only the required scoped patterns remain.
|
||||
assert.ElementsMatch(t, []string{
|
||||
"org/src: ci.yaml / build (pull_request)",
|
||||
"org/src: ci.yaml / lint (pull_request)",
|
||||
}, got)
|
||||
})
|
||||
|
||||
t.Run("several rules union their enabled contexts, deduplicated; a disabled rule contributes none", func(t *testing.T) {
|
||||
noSourceRepo := &repo_model.Repository{ID: consumer.ID, OwnerID: 99999} // no scoped sources, so only the rules' contexts gate
|
||||
a := &git_model.ProtectedBranch{EnableStatusCheck: true, StatusCheckContexts: []string{"a/check", "shared/check"}}
|
||||
b := &git_model.ProtectedBranch{EnableStatusCheck: true, StatusCheckContexts: []string{"b/check", "shared/check"}}
|
||||
off := &git_model.ProtectedBranch{EnableStatusCheck: false, StatusCheckContexts: []string{"off/check"}}
|
||||
got, err := EffectiveRequiredContexts(t.Context(), noSourceRepo, a, b, off)
|
||||
require.NoError(t, err)
|
||||
assert.ElementsMatch(t, []string{"a/check", "b/check", "shared/check"}, got)
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user