alt + click/enter to exclude labels`
issues.filter_label_no_select = All labels
+issues.filter_label_select_no_label = No Label
issues.filter_milestone = Milestone
issues.filter_milestone_all = All milestones
issues.filter_milestone_none = No milestones
@@ -1374,6 +1375,7 @@ issues.filter_project_all = All projects
issues.filter_project_none = No project
issues.filter_assignee = Assignee
issues.filter_assginee_no_select = All assignees
+issues.filter_assginee_no_assignee = No assignee
issues.filter_poster = Author
issues.filter_poster_no_select = All authors
issues.filter_type = Type
@@ -2193,8 +2195,13 @@ settings.protect_merge_whitelist_committers_desc = Allow only whitelisted users
settings.protect_merge_whitelist_users = Whitelisted users for merging:
settings.protect_merge_whitelist_teams = Whitelisted teams for merging:
settings.protect_check_status_contexts = Enable Status Check
-settings.protect_check_status_contexts_desc = Require status checks to pass before merging. Choose which status checks must pass before branches can be merged into a branch that matches this rule. When enabled, commits must first be pushed to another branch, then merged or pushed directly to a branch that matches this rule after status checks have passed. If no contexts are selected, the last commit must be successful regardless of context.
+settings.protect_status_check_patterns = Status check patterns:
+settings.protect_status_check_patterns_desc = Enter patterns to specify which status checks must pass before branches can be merged into a branch that matches this rule. Each line specifies a pattern. Patterns cannot be empty.
+settings.protect_check_status_contexts_desc = Require status checks to pass before merging. When enabled, commits must first be pushed to another branch, then merged or pushed directly to a branch that matches this rule after status checks have passed. If no contexts are matched, the last commit must be successful regardless of context.
settings.protect_check_status_contexts_list = Status checks found in the last week for this repository
+settings.protect_status_check_matched = Matched
+settings.protect_invalid_status_check_pattern = Invalid status check pattern: "%s".
+settings.protect_no_valid_status_check_patterns = No valid status check patterns.
settings.protect_required_approvals = Required approvals:
settings.protect_required_approvals_desc = Allow only to merge pull request with enough positive reviews.
settings.protect_approvals_whitelist_enabled = Restrict approvals to whitelisted users or teams
diff --git a/package-lock.json b/package-lock.json
index d00dda5cd7..7f30fe5ebc 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -35,6 +35,7 @@
"license-checker-webpack-plugin": "0.2.1",
"mermaid": "10.1.0",
"mini-css-extract-plugin": "2.7.5",
+ "minimatch": "9.0.0",
"monaco-editor": "0.38.0",
"monaco-editor-webpack-plugin": "7.0.1",
"pretty-ms": "8.0.0",
@@ -855,12 +856,34 @@
"url": "https://github.com/sponsors/epoberezkin"
}
},
+ "node_modules/@eslint/eslintrc/node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
"node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true
},
+ "node_modules/@eslint/eslintrc/node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/@eslint/js": {
"version": "8.40.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.40.0.tgz",
@@ -907,6 +930,28 @@
"node": ">=10.10.0"
}
},
+ "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/@humanwhocodes/config-array/node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/@humanwhocodes/module-importer": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
@@ -1480,6 +1525,28 @@
"node": "^12.20 || >=14.13"
}
},
+ "node_modules/@stoplight/spectral-core/node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/@stoplight/spectral-core/node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/@stoplight/spectral-formats": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@stoplight/spectral-formats/-/spectral-formats-1.5.0.tgz",
@@ -2668,12 +2735,11 @@
"dev": true
},
"node_modules/brace-expansion": {
- "version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dependencies": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
+ "balanced-match": "^1.0.0"
}
},
"node_modules/braces": {
@@ -4574,6 +4640,16 @@
"eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8"
}
},
+ "node_modules/eslint-plugin-import/node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
"node_modules/eslint-plugin-import/node_modules/debug": {
"version": "3.2.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
@@ -4595,6 +4671,18 @@
"node": ">=0.10.0"
}
},
+ "node_modules/eslint-plugin-import/node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/eslint-plugin-import/node_modules/semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
@@ -4767,12 +4855,34 @@
"url": "https://github.com/sponsors/epoberezkin"
}
},
+ "node_modules/eslint/node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
"node_modules/eslint/node_modules/json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true
},
+ "node_modules/eslint/node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/espree": {
"version": "9.5.2",
"resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz",
@@ -5273,6 +5383,26 @@
"resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
"integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="
},
+ "node_modules/glob/node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/glob/node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/global-modules": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz",
@@ -6396,6 +6526,26 @@
"webpack": "^4.4.0 || ^5.4.0"
}
},
+ "node_modules/license-checker-webpack-plugin/node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/license-checker-webpack-plugin/node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/license-checker-webpack-plugin/node_modules/semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
@@ -6645,15 +6795,6 @@
"node": ">=14"
}
},
- "node_modules/markdownlint-cli/node_modules/brace-expansion": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
- "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
- "dev": true,
- "dependencies": {
- "balanced-match": "^1.0.0"
- }
- },
"node_modules/markdownlint-cli/node_modules/commander": {
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
@@ -6691,21 +6832,6 @@
"integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==",
"dev": true
},
- "node_modules/markdownlint-cli/node_modules/minimatch": {
- "version": "9.0.0",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.0.tgz",
- "integrity": "sha512-0jJj8AvgKqWN05mrwuqi8QYKx1WmYSUoKSxu5Qhs9prezTz10sxAHGNZe9J9cqIJzta8DWsleh2KaVaLl6Ru2w==",
- "dev": true,
- "dependencies": {
- "brace-expansion": "^2.0.1"
- },
- "engines": {
- "node": ">=16 || 14 >=14.17"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
"node_modules/markdownlint-micromark": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/markdownlint-micromark/-/markdownlint-micromark-0.1.2.tgz",
@@ -6939,14 +7065,17 @@
}
},
"node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.0.tgz",
+ "integrity": "sha512-0jJj8AvgKqWN05mrwuqi8QYKx1WmYSUoKSxu5Qhs9prezTz10sxAHGNZe9J9cqIJzta8DWsleh2KaVaLl6Ru2w==",
"dependencies": {
- "brace-expansion": "^1.1.7"
+ "brace-expansion": "^2.0.1"
},
"engines": {
- "node": "*"
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/minimist": {
diff --git a/package.json b/package.json
index cf3f5af99a..6ec0d755dc 100644
--- a/package.json
+++ b/package.json
@@ -35,6 +35,7 @@
"license-checker-webpack-plugin": "0.2.1",
"mermaid": "10.1.0",
"mini-css-extract-plugin": "2.7.5",
+ "minimatch": "9.0.0",
"monaco-editor": "0.38.0",
"monaco-editor-webpack-plugin": "7.0.1",
"pretty-ms": "8.0.0",
diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go
index c2f30a01f4..66a4986139 100644
--- a/routers/web/repo/issue.go
+++ b/routers/web/repo/issue.go
@@ -170,8 +170,11 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
repo := ctx.Repo.Repository
var labelIDs []int64
+ // 1,-2 means including label 1 and excluding label 2
+ // 0 means issues with no label
+ // blank means labels will not be filtered for issues
selectLabels := ctx.FormString("labels")
- if len(selectLabels) > 0 && selectLabels != "0" {
+ if len(selectLabels) > 0 {
labelIDs, err = base.StringsToInt64s(strings.Split(selectLabels, ","))
if err != nil {
ctx.ServerError("StringsToInt64s", err)
diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go
index 070fc109dc..8821e74c95 100644
--- a/routers/web/repo/pull.go
+++ b/routers/web/repo/pull.go
@@ -45,6 +45,8 @@ import (
"code.gitea.io/gitea/services/gitdiff"
pull_service "code.gitea.io/gitea/services/pull"
repo_service "code.gitea.io/gitea/services/repository"
+
+ "github.com/gobwas/glob"
)
const (
@@ -575,7 +577,7 @@ func PrepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C
if pb != nil && pb.EnableStatusCheck {
ctx.Data["is_context_required"] = func(context string) bool {
for _, c := range pb.StatusCheckContexts {
- if c == context {
+ if gp, err := glob.Compile(c); err == nil && gp.Match(context) {
return true
}
}
diff --git a/routers/web/repo/setting_protected_branch.go b/routers/web/repo/setting_protected_branch.go
index 932bd373d7..1a944799c2 100644
--- a/routers/web/repo/setting_protected_branch.go
+++ b/routers/web/repo/setting_protected_branch.go
@@ -6,6 +6,7 @@ package repo
import (
"fmt"
"net/http"
+ "net/url"
"strings"
"time"
@@ -23,6 +24,8 @@ import (
"code.gitea.io/gitea/services/forms"
pull_service "code.gitea.io/gitea/services/pull"
"code.gitea.io/gitea/services/repository"
+
+ "github.com/gobwas/glob"
)
const (
@@ -115,21 +118,10 @@ func SettingsProtectedBranch(c *context.Context) {
c.Data["whitelist_users"] = strings.Join(base.Int64sToStrings(rule.WhitelistUserIDs), ",")
c.Data["merge_whitelist_users"] = strings.Join(base.Int64sToStrings(rule.MergeWhitelistUserIDs), ",")
c.Data["approvals_whitelist_users"] = strings.Join(base.Int64sToStrings(rule.ApprovalsWhitelistUserIDs), ",")
+ c.Data["status_check_contexts"] = strings.Join(rule.StatusCheckContexts, "\n")
contexts, _ := git_model.FindRepoRecentCommitStatusContexts(c, c.Repo.Repository.ID, 7*24*time.Hour) // Find last week status check contexts
- for _, ctx := range rule.StatusCheckContexts {
- var found bool
- for i := range contexts {
- if contexts[i] == ctx {
- found = true
- break
- }
- }
- if !found {
- contexts = append(contexts, ctx)
- }
- }
+ c.Data["recent_status_checks"] = contexts
- c.Data["branch_status_check_contexts"] = contexts
if c.Repo.Owner.IsOrganization() {
teams, err := organization.OrgFromUser(c.Repo.Owner).TeamsWithAccessToRepo(c.Repo.Repository.ID, perm.AccessModeRead)
if err != nil {
@@ -237,7 +229,27 @@ func SettingsProtectedBranchPost(ctx *context.Context) {
protectBranch.EnableStatusCheck = f.EnableStatusCheck
if f.EnableStatusCheck {
- protectBranch.StatusCheckContexts = f.StatusCheckContexts
+ patterns := strings.Split(strings.ReplaceAll(f.StatusCheckContexts, "\r", "\n"), "\n")
+ validPatterns := make([]string, 0, len(patterns))
+ for _, pattern := range patterns {
+ trimmed := strings.TrimSpace(pattern)
+ if trimmed == "" {
+ continue
+ }
+ if _, err := glob.Compile(trimmed); err != nil {
+ ctx.Flash.Error(ctx.Tr("repo.settings.protect_invalid_status_check_pattern", pattern))
+ ctx.Redirect(fmt.Sprintf("%s/settings/branches/edit?rule_name=%s", ctx.Repo.RepoLink, url.QueryEscape(protectBranch.RuleName)))
+ return
+ }
+ validPatterns = append(validPatterns, trimmed)
+ }
+ if len(validPatterns) == 0 {
+ // if status check is enabled, patterns slice is not allowed to be empty
+ ctx.Flash.Error(ctx.Tr("repo.settings.protect_no_valid_status_check_patterns"))
+ ctx.Redirect(fmt.Sprintf("%s/settings/branches/edit?rule_name=%s", ctx.Repo.RepoLink, url.QueryEscape(protectBranch.RuleName)))
+ return
+ }
+ protectBranch.StatusCheckContexts = validPatterns
} else {
protectBranch.StatusCheckContexts = nil
}
diff --git a/services/forms/repo_form.go b/services/forms/repo_form.go
index 5e57a7effb..bf0a30665d 100644
--- a/services/forms/repo_form.go
+++ b/services/forms/repo_form.go
@@ -207,7 +207,7 @@ type ProtectBranchForm struct {
MergeWhitelistUsers string
MergeWhitelistTeams string
EnableStatusCheck bool
- StatusCheckContexts []string
+ StatusCheckContexts string
RequiredApprovals int64
EnableApprovalsWhitelist bool
ApprovalsWhitelistUsers string
diff --git a/services/pull/commit_status.go b/services/pull/commit_status.go
index bfdb3f7291..51ba06da27 100644
--- a/services/pull/commit_status.go
+++ b/services/pull/commit_status.go
@@ -11,14 +11,46 @@ import (
git_model "code.gitea.io/gitea/models/git"
issues_model "code.gitea.io/gitea/models/issues"
"code.gitea.io/gitea/modules/git"
+ "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/structs"
+ "github.com/gobwas/glob"
"github.com/pkg/errors"
)
// MergeRequiredContextsCommitStatus returns a commit status state for given required contexts
func MergeRequiredContextsCommitStatus(commitStatuses []*git_model.CommitStatus, requiredContexts []string) structs.CommitStatusState {
- if len(requiredContexts) == 0 {
+ // matchedCount is the number of `CommitStatus.Context` that match any context of `requiredContexts`
+ matchedCount := 0
+ returnedStatus := structs.CommitStatusSuccess
+
+ if len(requiredContexts) > 0 {
+ requiredContextsGlob := make(map[string]glob.Glob, len(requiredContexts))
+ for _, ctx := range requiredContexts {
+ if gp, err := glob.Compile(ctx); err != nil {
+ log.Error("glob.Compile %s failed. Error: %v", ctx, err)
+ } else {
+ requiredContextsGlob[ctx] = gp
+ }
+ }
+
+ for _, commitStatus := range commitStatuses {
+ var targetStatus structs.CommitStatusState
+ for _, gp := range requiredContextsGlob {
+ if gp.Match(commitStatus.Context) {
+ targetStatus = commitStatus.State
+ matchedCount++
+ break
+ }
+ }
+
+ if targetStatus != "" && targetStatus.NoBetterThan(returnedStatus) {
+ returnedStatus = targetStatus
+ }
+ }
+ }
+
+ if matchedCount == 0 {
status := git_model.CalcCommitStatus(commitStatuses)
if status != nil {
return status.State
@@ -26,28 +58,6 @@ func MergeRequiredContextsCommitStatus(commitStatuses []*git_model.CommitStatus,
return structs.CommitStatusSuccess
}
- returnedStatus := structs.CommitStatusSuccess
- for _, ctx := range requiredContexts {
- var targetStatus structs.CommitStatusState
- for _, commitStatus := range commitStatuses {
- if commitStatus.Context == ctx {
- targetStatus = commitStatus.State
- break
- }
- }
-
- if targetStatus == "" {
- targetStatus = structs.CommitStatusPending
- commitStatuses = append(commitStatuses, &git_model.CommitStatus{
- State: targetStatus,
- Context: ctx,
- Description: "Pending",
- })
- }
- if targetStatus.NoBetterThan(returnedStatus) {
- returnedStatus = targetStatus
- }
- }
return returnedStatus
}
diff --git a/templates/repo/issue/list.tmpl b/templates/repo/issue/list.tmpl
index 68d40ffea7..7c2f73ca59 100644
--- a/templates/repo/issue/list.tmpl
+++ b/templates/repo/issue/list.tmpl
@@ -38,6 +38,7 @@
{{.locale.Tr "repo.issues.filter_label_exclude" | Safe}}
+ {{.locale.Tr "repo.issues.filter_label_select_no_label"}}
{{.locale.Tr "repo.issues.filter_label_no_select"}}
{{$previousExclusiveScope := "_no_scope"}}
{{range .Labels}}
@@ -156,6 +157,7 @@
{{svg "octicon-search" 16}}
+ {{.locale.Tr "repo.issues.filter_assginee_no_assignee"}}
{{.locale.Tr "repo.issues.filter_assginee_no_select"}}
{{range .Assignees}}
@@ -226,6 +228,9 @@
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
{{.locale.Tr "repo.settings.protect_status_check_patterns_desc"}}
| - - - - + {{.}} + {{$.locale.Tr "repo.settings.protect_status_check_matched"}} |