Skip to content

Commit 6f1cf76

Browse files
authored
Merge branch 'main' into fix-create-repo-page-layout
2 parents e320081 + a334a95 commit 6f1cf76

File tree

44 files changed

+425
-205
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+425
-205
lines changed

cmd/admin.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,10 @@ var (
288288
Value: "",
289289
Usage: "Custom icon URL for OAuth2 login source",
290290
},
291+
cli.BoolFlag{
292+
Name: "skip-local-2fa",
293+
Usage: "Set to true to skip local 2fa for users authenticated by this source",
294+
},
291295
}
292296

293297
microcmdAuthUpdateOauth = cli.Command{
@@ -616,6 +620,7 @@ func parseOAuth2Config(c *cli.Context) *oauth2.Source {
616620
OpenIDConnectAutoDiscoveryURL: c.String("auto-discover-url"),
617621
CustomURLMapping: customURLMapping,
618622
IconURL: c.String("icon-url"),
623+
SkipLocalTwoFA: c.Bool("skip-local-2fa"),
619624
}
620625
}
621626

integrations/git_test.go

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ func doBranchProtectPRMerge(baseCtx *APITestContext, dstPath string) func(t *tes
365365
t.Run("PushProtectedBranch", doGitPushTestRepository(dstPath, "origin", "protected"))
366366

367367
ctx := NewAPITestContext(t, baseCtx.Username, baseCtx.Reponame)
368-
t.Run("ProtectProtectedBranchNoWhitelist", doProtectBranch(ctx, "protected", ""))
368+
t.Run("ProtectProtectedBranchNoWhitelist", doProtectBranch(ctx, "protected", "", ""))
369369
t.Run("GenerateCommit", func(t *testing.T) {
370370
_, err := generateCommitWithNewData(littleSize, dstPath, "[email protected]", "User Two", "branch-data-file-")
371371
assert.NoError(t, err)
@@ -391,7 +391,15 @@ func doBranchProtectPRMerge(baseCtx *APITestContext, dstPath string) func(t *tes
391391
t.Run("MergePR2", doAPIMergePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr2.Index))
392392
t.Run("MergePR", doAPIMergePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index))
393393
t.Run("PullProtected", doGitPull(dstPath, "origin", "protected"))
394-
t.Run("ProtectProtectedBranchWhitelist", doProtectBranch(ctx, "protected", baseCtx.Username))
394+
395+
t.Run("ProtectProtectedBranchUnprotectedFilePaths", doProtectBranch(ctx, "protected", "", "unprotected-file-*"))
396+
t.Run("GenerateCommit", func(t *testing.T) {
397+
_, err := generateCommitWithNewData(littleSize, dstPath, "[email protected]", "User Two", "unprotected-file-")
398+
assert.NoError(t, err)
399+
})
400+
t.Run("PushUnprotectedFilesToProtectedBranch", doGitPushTestRepository(dstPath, "origin", "protected"))
401+
402+
t.Run("ProtectProtectedBranchWhitelist", doProtectBranch(ctx, "protected", baseCtx.Username, ""))
395403

396404
t.Run("CheckoutMaster", doGitCheckoutBranch(dstPath, "master"))
397405
t.Run("CreateBranchForced", doGitCreateBranch(dstPath, "toforce"))
@@ -406,28 +414,30 @@ func doBranchProtectPRMerge(baseCtx *APITestContext, dstPath string) func(t *tes
406414
}
407415
}
408416

409-
func doProtectBranch(ctx APITestContext, branch string, userToWhitelist string) func(t *testing.T) {
417+
func doProtectBranch(ctx APITestContext, branch string, userToWhitelist string, unprotectedFilePatterns string) func(t *testing.T) {
410418
// We are going to just use the owner to set the protection.
411419
return func(t *testing.T) {
412420
csrf := GetCSRF(t, ctx.Session, fmt.Sprintf("/%s/%s/settings/branches", url.PathEscape(ctx.Username), url.PathEscape(ctx.Reponame)))
413421

414422
if userToWhitelist == "" {
415423
// Change branch to protected
416424
req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/settings/branches/%s", url.PathEscape(ctx.Username), url.PathEscape(ctx.Reponame), url.PathEscape(branch)), map[string]string{
417-
"_csrf": csrf,
418-
"protected": "on",
425+
"_csrf": csrf,
426+
"protected": "on",
427+
"unprotected_file_patterns": unprotectedFilePatterns,
419428
})
420429
ctx.Session.MakeRequest(t, req, http.StatusFound)
421430
} else {
422431
user, err := models.GetUserByName(userToWhitelist)
423432
assert.NoError(t, err)
424433
// Change branch to protected
425434
req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/settings/branches/%s", url.PathEscape(ctx.Username), url.PathEscape(ctx.Reponame), url.PathEscape(branch)), map[string]string{
426-
"_csrf": csrf,
427-
"protected": "on",
428-
"enable_push": "whitelist",
429-
"enable_whitelist": "on",
430-
"whitelist_users": strconv.FormatInt(user.ID, 10),
435+
"_csrf": csrf,
436+
"protected": "on",
437+
"enable_push": "whitelist",
438+
"enable_whitelist": "on",
439+
"whitelist_users": strconv.FormatInt(user.ID, 10),
440+
"unprotected_file_patterns": unprotectedFilePatterns,
431441
})
432442
ctx.Session.MakeRequest(t, req, http.StatusFound)
433443
}

models/branches.go

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ type ProtectedBranch struct {
4343
DismissStaleApprovals bool `xorm:"NOT NULL DEFAULT false"`
4444
RequireSignedCommits bool `xorm:"NOT NULL DEFAULT false"`
4545
ProtectedFilePatterns string `xorm:"TEXT"`
46+
UnprotectedFilePatterns string `xorm:"TEXT"`
4647

4748
CreatedUnix timeutil.TimeStamp `xorm:"created"`
4849
UpdatedUnix timeutil.TimeStamp `xorm:"updated"`
@@ -214,8 +215,17 @@ func (protectBranch *ProtectedBranch) MergeBlockedByOutdatedBranch(pr *PullReque
214215

215216
// GetProtectedFilePatterns parses a semicolon separated list of protected file patterns and returns a glob.Glob slice
216217
func (protectBranch *ProtectedBranch) GetProtectedFilePatterns() []glob.Glob {
218+
return getFilePatterns(protectBranch.ProtectedFilePatterns)
219+
}
220+
221+
// GetUnprotectedFilePatterns parses a semicolon separated list of unprotected file patterns and returns a glob.Glob slice
222+
func (protectBranch *ProtectedBranch) GetUnprotectedFilePatterns() []glob.Glob {
223+
return getFilePatterns(protectBranch.UnprotectedFilePatterns)
224+
}
225+
226+
func getFilePatterns(filePatterns string) []glob.Glob {
217227
extarr := make([]glob.Glob, 0, 10)
218-
for _, expr := range strings.Split(strings.ToLower(protectBranch.ProtectedFilePatterns), ";") {
228+
for _, expr := range strings.Split(strings.ToLower(filePatterns), ";") {
219229
expr = strings.TrimSpace(expr)
220230
if expr != "" {
221231
if g, err := glob.Compile(expr, '.', '/'); err != nil {
@@ -260,6 +270,28 @@ func (protectBranch *ProtectedBranch) IsProtectedFile(patterns []glob.Glob, path
260270
return r
261271
}
262272

273+
// IsUnprotectedFile return if path is unprotected
274+
func (protectBranch *ProtectedBranch) IsUnprotectedFile(patterns []glob.Glob, path string) bool {
275+
if len(patterns) == 0 {
276+
patterns = protectBranch.GetUnprotectedFilePatterns()
277+
if len(patterns) == 0 {
278+
return false
279+
}
280+
}
281+
282+
lpath := strings.ToLower(strings.TrimSpace(path))
283+
284+
r := false
285+
for _, pat := range patterns {
286+
if pat.Match(lpath) {
287+
r = true
288+
break
289+
}
290+
}
291+
292+
return r
293+
}
294+
263295
// GetProtectedBranchBy getting protected branch by ID/Name
264296
func GetProtectedBranchBy(repoID int64, branchName string) (*ProtectedBranch, error) {
265297
return getProtectedBranchBy(x, repoID, branchName)

models/migrations/migrations.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,8 @@ var migrations = []Migration{
340340
NewMigration("RecreateIssueResourceIndexTable to have a primary key instead of an unique index", recreateIssueResourceIndexTable),
341341
// v193 -> v194
342342
NewMigration("Add repo id column for attachment table", addRepoIDForAttachment),
343+
// v194 -> v195
344+
NewMigration("Add Branch Protection Unprotected Files Column", addBranchProtectionUnprotectedFilesColumn),
343345
}
344346

345347
// GetCurrentDBVersion returns the current db version

models/migrations/v194.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2021 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package migrations
6+
7+
import (
8+
"fmt"
9+
10+
"xorm.io/xorm"
11+
)
12+
13+
func addBranchProtectionUnprotectedFilesColumn(x *xorm.Engine) error {
14+
type ProtectedBranch struct {
15+
UnprotectedFilePatterns string `xorm:"TEXT"`
16+
}
17+
18+
if err := x.Sync2(new(ProtectedBranch)); err != nil {
19+
return fmt.Errorf("Sync2: %v", err)
20+
}
21+
return nil
22+
}

modules/context/repo.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -547,7 +547,7 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
547547
return
548548
}
549549

550-
tags, err := ctx.Repo.GitRepo.GetTags()
550+
tags, err := ctx.Repo.GitRepo.GetTags(0, 0)
551551
if err != nil {
552552
ctx.ServerError("GetTags", err)
553553
return

modules/convert/convert.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ func ToBranchProtection(bp *models.ProtectedBranch) *api.BranchProtection {
127127
DismissStaleApprovals: bp.DismissStaleApprovals,
128128
RequireSignedCommits: bp.RequireSignedCommits,
129129
ProtectedFilePatterns: bp.ProtectedFilePatterns,
130+
UnprotectedFilePatterns: bp.UnprotectedFilePatterns,
130131
Created: bp.CreatedUnix.AsTime(),
131132
Updated: bp.UpdatedUnix.AsTime(),
132133
}

modules/convert/issue.go

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@
55
package convert
66

77
import (
8+
"fmt"
89
"strings"
910

1011
"code.gitea.io/gitea/models"
12+
"code.gitea.io/gitea/modules/log"
13+
"code.gitea.io/gitea/modules/setting"
1114
api "code.gitea.io/gitea/modules/structs"
1215
)
1316

@@ -25,6 +28,9 @@ func ToAPIIssue(issue *models.Issue) *api.Issue {
2528
if err := issue.LoadRepo(); err != nil {
2629
return &api.Issue{}
2730
}
31+
if err := issue.Repo.GetOwner(); err != nil {
32+
return &api.Issue{}
33+
}
2834

2935
apiIssue := &api.Issue{
3036
ID: issue.ID,
@@ -35,7 +41,7 @@ func ToAPIIssue(issue *models.Issue) *api.Issue {
3541
Title: issue.Title,
3642
Body: issue.Content,
3743
Ref: issue.Ref,
38-
Labels: ToLabelList(issue.Labels),
44+
Labels: ToLabelList(issue.Labels, issue.Repo, issue.Repo.Owner),
3945
State: issue.State(),
4046
IsLocked: issue.IsLocked,
4147
Comments: issue.NumComments,
@@ -168,20 +174,37 @@ func ToTrackedTimeList(tl models.TrackedTimeList) api.TrackedTimeList {
168174
}
169175

170176
// ToLabel converts Label to API format
171-
func ToLabel(label *models.Label) *api.Label {
172-
return &api.Label{
177+
func ToLabel(label *models.Label, repo *models.Repository, org *models.User) *api.Label {
178+
result := &api.Label{
173179
ID: label.ID,
174180
Name: label.Name,
175181
Color: strings.TrimLeft(label.Color, "#"),
176182
Description: label.Description,
177183
}
184+
185+
// calculate URL
186+
if label.BelongsToRepo() && repo != nil {
187+
if repo != nil {
188+
result.URL = fmt.Sprintf("%s/labels/%d", repo.APIURL(), label.ID)
189+
} else {
190+
log.Error("ToLabel did not get repo to calculate url for label with id '%d'", label.ID)
191+
}
192+
} else { // BelongsToOrg
193+
if org != nil {
194+
result.URL = fmt.Sprintf("%sapi/v1/orgs/%s/labels/%d", setting.AppURL, org.Name, label.ID)
195+
} else {
196+
log.Error("ToLabel did not get org to calculate url for label with id '%d'", label.ID)
197+
}
198+
}
199+
200+
return result
178201
}
179202

180203
// ToLabelList converts list of Label to API format
181-
func ToLabelList(labels []*models.Label) []*api.Label {
204+
func ToLabelList(labels []*models.Label, repo *models.Repository, org *models.User) []*api.Label {
182205
result := make([]*api.Label, len(labels))
183206
for i := range labels {
184-
result[i] = ToLabel(labels[i])
207+
result[i] = ToLabel(labels[i], repo, org)
185208
}
186209
return result
187210
}

modules/convert/issue_test.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
package convert
66

77
import (
8+
"fmt"
89
"testing"
910
"time"
1011

1112
"code.gitea.io/gitea/models"
13+
"code.gitea.io/gitea/modules/setting"
1214
api "code.gitea.io/gitea/modules/structs"
1315
"code.gitea.io/gitea/modules/timeutil"
1416

@@ -18,11 +20,13 @@ import (
1820
func TestLabel_ToLabel(t *testing.T) {
1921
assert.NoError(t, models.PrepareTestDatabase())
2022
label := models.AssertExistsAndLoadBean(t, &models.Label{ID: 1}).(*models.Label)
23+
repo := models.AssertExistsAndLoadBean(t, &models.Repository{ID: label.RepoID}).(*models.Repository)
2124
assert.Equal(t, &api.Label{
2225
ID: label.ID,
2326
Name: label.Name,
2427
Color: "abcdef",
25-
}, ToLabel(label))
28+
URL: fmt.Sprintf("%sapi/v1/repos/user2/repo1/labels/%d", setting.AppURL, label.ID),
29+
}, ToLabel(label, repo, nil))
2630
}
2731

2832
func TestMilestone_APIFormat(t *testing.T) {

modules/git/diff.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"context"
1111
"fmt"
1212
"io"
13+
"os"
1314
"os/exec"
1415
"regexp"
1516
"strconv"
@@ -273,3 +274,46 @@ func CutDiffAroundLine(originalDiff io.Reader, line int64, old bool, numbersOfLi
273274
oldBegin, oldNumOfLines, newBegin, newNumOfLines)
274275
return strings.Join(newHunk, "\n"), nil
275276
}
277+
278+
// GetAffectedFiles returns the affected files between two commits
279+
func GetAffectedFiles(oldCommitID, newCommitID string, env []string, repo *Repository) ([]string, error) {
280+
stdoutReader, stdoutWriter, err := os.Pipe()
281+
if err != nil {
282+
log.Error("Unable to create os.Pipe for %s", repo.Path)
283+
return nil, err
284+
}
285+
defer func() {
286+
_ = stdoutReader.Close()
287+
_ = stdoutWriter.Close()
288+
}()
289+
290+
affectedFiles := make([]string, 0, 32)
291+
292+
// Run `git diff --name-only` to get the names of the changed files
293+
err = NewCommand("diff", "--name-only", oldCommitID, newCommitID).
294+
RunInDirTimeoutEnvFullPipelineFunc(env, -1, repo.Path,
295+
stdoutWriter, nil, nil,
296+
func(ctx context.Context, cancel context.CancelFunc) error {
297+
// Close the writer end of the pipe to begin processing
298+
_ = stdoutWriter.Close()
299+
defer func() {
300+
// Close the reader on return to terminate the git command if necessary
301+
_ = stdoutReader.Close()
302+
}()
303+
// Now scan the output from the command
304+
scanner := bufio.NewScanner(stdoutReader)
305+
for scanner.Scan() {
306+
path := strings.TrimSpace(scanner.Text())
307+
if len(path) == 0 {
308+
continue
309+
}
310+
affectedFiles = append(affectedFiles, path)
311+
}
312+
return scanner.Err()
313+
})
314+
if err != nil {
315+
log.Error("Unable to get affected files for commits from %s to %s in %s: %v", oldCommitID, newCommitID, repo.Path, err)
316+
}
317+
318+
return affectedFiles, err
319+
}

modules/git/repo_tag_gogit.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ func (repo *Repository) IsTagExist(name string) bool {
2121
}
2222

2323
// GetTags returns all tags of the repository.
24-
func (repo *Repository) GetTags() ([]string, error) {
24+
// returning at most limit tags, or all if limit is 0.
25+
func (repo *Repository) GetTags(skip, limit int) ([]string, error) {
2526
var tagNames []string
2627

2728
tags, err := repo.gogitRepo.Tags()
@@ -40,5 +41,15 @@ func (repo *Repository) GetTags() ([]string, error) {
4041
tagNames[i], tagNames[j] = tagNames[j], tagNames[i]
4142
}
4243

44+
// since we have to reverse order we can paginate only afterwards
45+
if len(tagNames) < skip {
46+
tagNames = []string{}
47+
} else {
48+
tagNames = tagNames[skip:]
49+
}
50+
if limit != 0 && len(tagNames) > limit {
51+
tagNames = tagNames[:limit]
52+
}
53+
4354
return tagNames, nil
4455
}

modules/git/repo_tag_nogogit.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ func (repo *Repository) IsTagExist(name string) bool {
1818
}
1919

2020
// GetTags returns all tags of the repository.
21-
func (repo *Repository) GetTags() (tags []string, err error) {
22-
tags, _, err = callShowRef(repo.Path, TagPrefix, "--tags", 0, 0)
21+
// returning at most limit tags, or all if limit is 0.
22+
func (repo *Repository) GetTags(skip, limit int) (tags []string, err error) {
23+
tags, _, err = callShowRef(repo.Path, TagPrefix, "--tags", skip, limit)
2324
return
2425
}

0 commit comments

Comments
 (0)