diff --git a/routers/api/v1/repo/branch.go b/routers/api/v1/repo/branch.go index 6a2944b142..79ccfbbd19 100644 --- a/routers/api/v1/repo/branch.go +++ b/routers/api/v1/repo/branch.go @@ -22,6 +22,8 @@ import ( "code.gitea.io/gitea/routers/api/v1/utils" pull_service "code.gitea.io/gitea/services/pull" repo_service "code.gitea.io/gitea/services/repository" + + "github.com/gobwas/glob" ) // GetBranch get a branch of a repository @@ -409,12 +411,16 @@ func CreateBranchProtection(ctx *context.APIContext) { form := web.GetForm(ctx).(*api.CreateBranchProtectionOption) repo := ctx.Repo.Repository - // Currently protection must match an actual branch - // FIXME: we should allow glob match - if !git.IsBranchExist(ctx.Req.Context(), ctx.Repo.Repository.RepoPath(), form.RuleName) { - ctx.NotFound() + g, err := glob.Compile(form.RuleName, '/') + if err != nil { + ctx.Error(http.StatusBadRequest, "Create branch protection", "Branch protection rule name is not right") return } + isPlainRule := g.Match(form.RuleName) + isBranchName := isPlainRule + if isBranchName { + isBranchName = git.IsBranchExist(ctx.Req.Context(), ctx.Repo.Repository.RepoPath(), form.RuleName) + } protectBranch, err := git_model.GetProtectedBranchRuleByName(ctx, repo.ID, form.RuleName) if err != nil { @@ -521,18 +527,38 @@ func CreateBranchProtection(ctx *context.APIContext) { return } - // FIXME: since we only need to recheck files protected rules, we could improve this - matchedBranches, err := git_model.FindAllMatchedBranches(ctx, ctx.Repo.GitRepo, form.RuleName) - if err != nil { - ctx.Error(http.StatusInternalServerError, "FindAllMatchedBranches", err) - return - } - - for _, branchName := range matchedBranches { - if err = pull_service.CheckPRsForBaseBranch(ctx.Repo.Repository, branchName); err != nil { + if isBranchName { + if err = pull_service.CheckPRsForBaseBranch(ctx.Repo.Repository, form.RuleName); err != nil { ctx.Error(http.StatusInternalServerError, "CheckPRsForBaseBranch", err) return } + } else { + if !isPlainRule { + if ctx.Repo.GitRepo == nil { + ctx.Repo.GitRepo, err = git.OpenRepository(ctx, ctx.Repo.Repository.RepoPath()) + if err != nil { + ctx.Error(http.StatusInternalServerError, "OpenRepository", err) + return + } + defer func() { + ctx.Repo.GitRepo.Close() + ctx.Repo.GitRepo = nil + }() + } + // FIXME: since we only need to recheck files protected rules, we could improve this + matchedBranches, err := git_model.FindAllMatchedBranches(ctx, ctx.Repo.GitRepo, form.RuleName) + if err != nil { + ctx.Error(http.StatusInternalServerError, "FindAllMatchedBranches", err) + return + } + + for _, branchName := range matchedBranches { + if err = pull_service.CheckPRsForBaseBranch(ctx.Repo.Repository, branchName); err != nil { + ctx.Error(http.StatusInternalServerError, "CheckPRsForBaseBranch", err) + return + } + } + } } // Reload from db to get all whitelists @@ -765,18 +791,50 @@ func EditBranchProtection(ctx *context.APIContext) { return } - // FIXME: since we only need to recheck files protected rules, we could improve this - matchedBranches, err := git_model.FindAllMatchedBranches(ctx, ctx.Repo.GitRepo, protectBranch.BranchName) + g, err := glob.Compile(bpName, '/') if err != nil { - ctx.Error(http.StatusInternalServerError, "FindAllMatchedBranches", err) + ctx.Error(http.StatusBadRequest, "Create branch protection", "Branch protection rule name is not right") return } + isPlainRule := g.Match(bpName) + isBranchName := isPlainRule + if isBranchName { + isBranchName = git.IsBranchExist(ctx.Req.Context(), ctx.Repo.Repository.RepoPath(), bpName) + } - for _, branchName := range matchedBranches { - if err = pull_service.CheckPRsForBaseBranch(ctx.Repo.Repository, branchName); err != nil { + if isBranchName { + if err = pull_service.CheckPRsForBaseBranch(ctx.Repo.Repository, bpName); err != nil { ctx.Error(http.StatusInternalServerError, "CheckPrsForBaseBranch", err) return } + } else { + if !isPlainRule { + if ctx.Repo.GitRepo == nil { + ctx.Repo.GitRepo, err = git.OpenRepository(ctx, ctx.Repo.Repository.RepoPath()) + if err != nil { + ctx.Error(http.StatusInternalServerError, "OpenRepository", err) + return + } + defer func() { + ctx.Repo.GitRepo.Close() + ctx.Repo.GitRepo = nil + }() + } + + // FIXME: since we only need to recheck files protected rules, we could improve this + matchedBranches, err := git_model.FindAllMatchedBranches(ctx, ctx.Repo.GitRepo, protectBranch.BranchName) + if err != nil { + ctx.Error(http.StatusInternalServerError, "FindAllMatchedBranches", err) + return + } + + for _, branchName := range matchedBranches { + if err = pull_service.CheckPRsForBaseBranch(ctx.Repo.Repository, branchName); err != nil { + ctx.Error(http.StatusInternalServerError, "CheckPrsForBaseBranch", err) + return + } + } + } } // Reload from db to ensure get all whitelists diff --git a/tests/integration/api_branch_test.go b/tests/integration/api_branch_test.go index bdfdd3c752..4f61598e6d 100644 --- a/tests/integration/api_branch_test.go +++ b/tests/integration/api_branch_test.go @@ -176,8 +176,8 @@ func testAPICreateBranch(t testing.TB, session *TestSession, user, repo, oldBran func TestAPIBranchProtection(t *testing.T) { defer tests.PrepareTestEnv(t)() - // Branch protection only on branch that exist - testAPICreateBranchProtection(t, "master/doesnotexist", http.StatusNotFound) + // Branch protection on branch that not exist + testAPICreateBranchProtection(t, "master/doesnotexist", http.StatusCreated) // Get branch protection on branch that exist but not branch protection testAPIGetBranchProtection(t, "master", http.StatusNotFound)