loading up the forgejo repo on tangled to test page performance
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request '[gitea] week 2024-47 cherry pick (gitea/main -> forgejo)' (#5997) from earl-warren/wcp/2024-47 into forgejo

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/5997
Reviewed-by: Gusted <gusted@noreply.codeberg.org>

+451 -290
-3
.deadcode-out
··· 289 289 code.gitea.io/gitea/services/repository 290 290 IsErrForkAlreadyExist 291 291 292 - code.gitea.io/gitea/services/repository/archiver 293 - ArchiveRepository 294 - 295 292 code.gitea.io/gitea/services/repository/files 296 293 ContentType.String 297 294 GetFileResponseFromCommit
+3
models/actions/run.go
··· 254 254 } 255 255 256 256 // InsertRun inserts a run 257 + // The title will be cut off at 255 characters if it's longer than 255 characters. 257 258 func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWorkflow) error { 258 259 ctx, commiter, err := db.TxContext(ctx) 259 260 if err != nil { ··· 266 267 return err 267 268 } 268 269 run.Index = index 270 + run.Title, _ = util.SplitStringAtByteN(run.Title, 255) 269 271 270 272 if err := db.Insert(ctx, run); err != nil { 271 273 return err ··· 391 393 if len(cols) > 0 { 392 394 sess.Cols(cols...) 393 395 } 396 + run.Title, _ = util.SplitStringAtByteN(run.Title, 255) 394 397 affected, err := sess.Update(run) 395 398 if err != nil { 396 399 return err
+2
models/actions/runner.go
··· 271 271 // UpdateRunner updates runner's information. 272 272 func UpdateRunner(ctx context.Context, r *ActionRunner, cols ...string) error { 273 273 e := db.GetEngine(ctx) 274 + r.Name, _ = util.SplitStringAtByteN(r.Name, 255) 274 275 var err error 275 276 if len(cols) == 0 { 276 277 _, err = e.ID(r.ID).AllCols().Update(r) ··· 312 313 // Remove OwnerID to avoid confusion; it's not worth returning an error here. 313 314 t.OwnerID = 0 314 315 } 316 + t.Name, _ = util.SplitStringAtByteN(t.Name, 255) 315 317 return db.Insert(ctx, t) 316 318 } 317 319
+2
models/actions/schedule.go
··· 12 12 repo_model "code.gitea.io/gitea/models/repo" 13 13 user_model "code.gitea.io/gitea/models/user" 14 14 "code.gitea.io/gitea/modules/timeutil" 15 + "code.gitea.io/gitea/modules/util" 15 16 webhook_module "code.gitea.io/gitea/modules/webhook" 16 17 ) 17 18 ··· 67 68 68 69 // Loop through each schedule row 69 70 for _, row := range rows { 71 + row.Title, _ = util.SplitStringAtByteN(row.Title, 255) 70 72 // Create new schedule row 71 73 if err = db.Insert(ctx, row); err != nil { 72 74 return err
+3 -1
models/actions/task.go
··· 341 341 // UpdateTaskByState updates the task by the state. 342 342 // It will always update the task if the state is not final, even there is no change. 343 343 // So it will update ActionTask.Updated to avoid the task being judged as a zombie task. 344 - func UpdateTaskByState(ctx context.Context, state *runnerv1.TaskState) (*ActionTask, error) { 344 + func UpdateTaskByState(ctx context.Context, runnerID int64, state *runnerv1.TaskState) (*ActionTask, error) { 345 345 stepStates := map[int64]*runnerv1.StepState{} 346 346 for _, v := range state.Steps { 347 347 stepStates[v.Id] = v ··· 360 360 return nil, err 361 361 } else if !has { 362 362 return nil, util.ErrNotExist 363 + } else if runnerID != task.RunnerID { 364 + return nil, fmt.Errorf("invalid runner for task") 363 365 } 364 366 365 367 if task.Status.IsDone() {
+6
models/activities/action.go
··· 250 250 // GetRepoUserName returns the name of the action repository owner. 251 251 func (a *Action) GetRepoUserName(ctx context.Context) string { 252 252 a.loadRepo(ctx) 253 + if a.Repo == nil { 254 + return "(non-existing-repo)" 255 + } 253 256 return a.Repo.OwnerName 254 257 } 255 258 ··· 262 265 // GetRepoName returns the name of the action repository. 263 266 func (a *Action) GetRepoName(ctx context.Context) string { 264 267 a.loadRepo(ctx) 268 + if a.Repo == nil { 269 + return "(non-existing-repo)" 270 + } 265 271 return a.Repo.Name 266 272 } 267 273
+4
models/issues/issue_update.go
··· 21 21 "code.gitea.io/gitea/modules/references" 22 22 api "code.gitea.io/gitea/modules/structs" 23 23 "code.gitea.io/gitea/modules/timeutil" 24 + "code.gitea.io/gitea/modules/util" 24 25 25 26 "xorm.io/builder" 26 27 ) ··· 154 155 } 155 156 defer committer.Close() 156 157 158 + issue.Title, _ = util.SplitStringAtByteN(issue.Title, 255) 157 159 if err = UpdateIssueCols(ctx, issue, "name"); err != nil { 158 160 return fmt.Errorf("updateIssueCols: %w", err) 159 161 } ··· 409 411 } 410 412 411 413 // NewIssue creates new issue with labels for repository. 414 + // The title will be cut off at 255 characters if it's longer than 255 characters. 412 415 func NewIssue(ctx context.Context, repo *repo_model.Repository, issue *Issue, labelIDs []int64, uuids []string) (err error) { 413 416 ctx, committer, err := db.TxContext(ctx) 414 417 if err != nil { ··· 422 425 } 423 426 424 427 issue.Index = idx 428 + issue.Title, _ = util.SplitStringAtByteN(issue.Title, 255) 425 429 426 430 if err = NewIssueWithIndex(ctx, issue.Poster, NewIssueOptions{ 427 431 Repo: repo,
+1
models/issues/pull.go
··· 566 566 } 567 567 568 568 issue.Index = idx 569 + issue.Title, _ = util.SplitStringAtByteN(issue.Title, 255) 569 570 570 571 if err = NewIssueWithIndex(ctx, issue.Poster, NewIssueOptions{ 571 572 Repo: repo,
-78
models/organization/mini_org.go
··· 1 - // Copyright 2022 The Gitea Authors. All rights reserved. 2 - // SPDX-License-Identifier: MIT 3 - 4 - package organization 5 - 6 - import ( 7 - "context" 8 - "fmt" 9 - "strings" 10 - 11 - "code.gitea.io/gitea/models/db" 12 - repo_model "code.gitea.io/gitea/models/repo" 13 - "code.gitea.io/gitea/models/unit" 14 - user_model "code.gitea.io/gitea/models/user" 15 - 16 - "xorm.io/builder" 17 - ) 18 - 19 - // MinimalOrg represents a simple organization with only the needed columns 20 - type MinimalOrg = Organization 21 - 22 - // GetUserOrgsList returns all organizations the given user has access to 23 - func GetUserOrgsList(ctx context.Context, user *user_model.User) ([]*MinimalOrg, error) { 24 - schema, err := db.TableInfo(new(user_model.User)) 25 - if err != nil { 26 - return nil, err 27 - } 28 - 29 - outputCols := []string{ 30 - "id", 31 - "name", 32 - "full_name", 33 - "visibility", 34 - "avatar", 35 - "avatar_email", 36 - "use_custom_avatar", 37 - } 38 - 39 - groupByCols := &strings.Builder{} 40 - for _, col := range outputCols { 41 - fmt.Fprintf(groupByCols, "`%s`.%s,", schema.Name, col) 42 - } 43 - groupByStr := groupByCols.String() 44 - groupByStr = groupByStr[0 : len(groupByStr)-1] 45 - 46 - sess := db.GetEngine(ctx) 47 - sess = sess.Select(groupByStr+", count(distinct repo_id) as org_count"). 48 - Table("user"). 49 - Join("INNER", "team", "`team`.org_id = `user`.id"). 50 - Join("INNER", "team_user", "`team`.id = `team_user`.team_id"). 51 - Join("LEFT", builder. 52 - Select("id as repo_id, owner_id as repo_owner_id"). 53 - From("repository"). 54 - Where(repo_model.AccessibleRepositoryCondition(user, unit.TypeInvalid)), "`repository`.repo_owner_id = `team`.org_id"). 55 - Where("`team_user`.uid = ?", user.ID). 56 - GroupBy(groupByStr) 57 - 58 - type OrgCount struct { 59 - Organization `xorm:"extends"` 60 - OrgCount int 61 - } 62 - 63 - orgCounts := make([]*OrgCount, 0, 10) 64 - 65 - if err := sess. 66 - Asc("`user`.name"). 67 - Find(&orgCounts); err != nil { 68 - return nil, err 69 - } 70 - 71 - orgs := make([]*MinimalOrg, len(orgCounts)) 72 - for i, orgCount := range orgCounts { 73 - orgCount.Organization.NumRepos = orgCount.OrgCount 74 - orgs[i] = &orgCount.Organization 75 - } 76 - 77 - return orgs, nil 78 - }
+13 -62
models/organization/org.go
··· 24 24 "xorm.io/builder" 25 25 ) 26 26 27 - // ________ .__ __ .__ 28 - // \_____ \_______ _________ ____ |__|____________ _/ |_|__| ____ ____ 29 - // / | \_ __ \/ ___\__ \ / \| \___ /\__ \\ __\ |/ _ \ / \ 30 - // / | \ | \/ /_/ > __ \| | \ |/ / / __ \| | | ( <_> ) | \ 31 - // \_______ /__| \___ (____ /___| /__/_____ \(____ /__| |__|\____/|___| / 32 - // \/ /_____/ \/ \/ \/ \/ \/ 33 - 34 27 // ErrOrgNotExist represents a "OrgNotExist" kind of error. 35 28 type ErrOrgNotExist struct { 36 29 ID int64 ··· 141 134 } 142 135 143 136 // GetMembers returns all members of organization. 144 - func (org *Organization) GetMembers(ctx context.Context) (user_model.UserList, map[int64]bool, error) { 137 + func (org *Organization) GetMembers(ctx context.Context, doer *user_model.User) (user_model.UserList, map[int64]bool, error) { 145 138 return FindOrgMembers(ctx, &FindOrgMembersOpts{ 139 + Doer: doer, 146 140 OrgID: org.ID, 147 141 }) 148 142 } ··· 195 189 // FindOrgMembersOpts represensts find org members conditions 196 190 type FindOrgMembersOpts struct { 197 191 db.ListOptions 198 - OrgID int64 199 - PublicOnly bool 192 + Doer *user_model.User 193 + IsDoerMember bool 194 + OrgID int64 195 + } 196 + 197 + func (opts FindOrgMembersOpts) PublicOnly() bool { 198 + return opts.Doer == nil || !(opts.IsDoerMember || opts.Doer.IsAdmin) 200 199 } 201 200 202 201 // CountOrgMembers counts the organization's members 203 202 func CountOrgMembers(ctx context.Context, opts *FindOrgMembersOpts) (int64, error) { 204 203 sess := db.GetEngine(ctx).Where("org_id=?", opts.OrgID) 205 - if opts.PublicOnly { 204 + if opts.PublicOnly() { 206 205 sess.And("is_public = ?", true) 207 206 } 207 + 208 208 return sess.Count(new(OrgUser)) 209 209 } 210 210 ··· 439 439 And("team_user.org_id = ?", orgID).Find(&users) 440 440 } 441 441 442 - // SearchOrganizationsOptions options to filter organizations 443 - type SearchOrganizationsOptions struct { 444 - db.ListOptions 445 - All bool 446 - } 447 - 448 - // FindOrgOptions finds orgs options 449 - type FindOrgOptions struct { 450 - db.ListOptions 451 - UserID int64 452 - IncludePrivate bool 453 - } 454 - 455 - func queryUserOrgIDs(userID int64, includePrivate bool) *builder.Builder { 456 - cond := builder.Eq{"uid": userID} 457 - if !includePrivate { 458 - cond["is_public"] = true 459 - } 460 - return builder.Select("org_id").From("org_user").Where(cond) 461 - } 462 - 463 - func (opts FindOrgOptions) ToConds() builder.Cond { 464 - var cond builder.Cond = builder.Eq{"`user`.`type`": user_model.UserTypeOrganization} 465 - if opts.UserID > 0 { 466 - cond = cond.And(builder.In("`user`.`id`", queryUserOrgIDs(opts.UserID, opts.IncludePrivate))) 467 - } 468 - if !opts.IncludePrivate { 469 - cond = cond.And(builder.Eq{"`user`.visibility": structs.VisibleTypePublic}) 470 - } 471 - return cond 472 - } 473 - 474 - func (opts FindOrgOptions) ToOrders() string { 475 - return "`user`.name ASC" 476 - } 477 - 478 442 // HasOrgOrUserVisible tells if the given user can see the given org or user 479 443 func HasOrgOrUserVisible(ctx context.Context, orgOrUser, user *user_model.User) bool { 480 444 // If user is nil, it's an anonymous user/request. ··· 507 471 return false 508 472 } 509 473 510 - // GetOrgsCanCreateRepoByUserID returns a list of organizations where given user ID 511 - // are allowed to create repos. 512 - func GetOrgsCanCreateRepoByUserID(ctx context.Context, userID int64) ([]*Organization, error) { 513 - orgs := make([]*Organization, 0, 10) 514 - 515 - return orgs, db.GetEngine(ctx).Where(builder.In("id", builder.Select("`user`.id").From("`user`"). 516 - Join("INNER", "`team_user`", "`team_user`.org_id = `user`.id"). 517 - Join("INNER", "`team`", "`team`.id = `team_user`.team_id"). 518 - Where(builder.Eq{"`team_user`.uid": userID}). 519 - And(builder.Eq{"`team`.authorize": perm.AccessModeOwner}.Or(builder.Eq{"`team`.can_create_org_repo": true})))). 520 - Asc("`user`.name"). 521 - Find(&orgs) 522 - } 523 - 524 474 // GetOrgUsersByOrgID returns all organization-user relations by organization ID. 525 475 func GetOrgUsersByOrgID(ctx context.Context, opts *FindOrgMembersOpts) ([]*OrgUser, error) { 526 476 sess := db.GetEngine(ctx).Where("org_id=?", opts.OrgID) 527 - if opts.PublicOnly { 477 + if opts.PublicOnly() { 528 478 sess.And("is_public = ?", true) 529 479 } 480 + 530 481 if opts.ListOptions.PageSize > 0 { 531 482 sess = db.SetSessionPagination(sess, opts) 532 483
+138
models/organization/org_list.go
··· 1 + // Copyright 2024 The Gitea Authors. All rights reserved. 2 + // SPDX-License-Identifier: MIT 3 + 4 + package organization 5 + 6 + import ( 7 + "context" 8 + "fmt" 9 + "strings" 10 + 11 + "code.gitea.io/gitea/models/db" 12 + "code.gitea.io/gitea/models/perm" 13 + user_model "code.gitea.io/gitea/models/user" 14 + "code.gitea.io/gitea/modules/structs" 15 + 16 + "xorm.io/builder" 17 + ) 18 + 19 + // SearchOrganizationsOptions options to filter organizations 20 + type SearchOrganizationsOptions struct { 21 + db.ListOptions 22 + All bool 23 + } 24 + 25 + // FindOrgOptions finds orgs options 26 + type FindOrgOptions struct { 27 + db.ListOptions 28 + UserID int64 29 + IncludePrivate bool 30 + } 31 + 32 + func queryUserOrgIDs(userID int64, includePrivate bool) *builder.Builder { 33 + cond := builder.Eq{"uid": userID} 34 + if !includePrivate { 35 + cond["is_public"] = true 36 + } 37 + return builder.Select("org_id").From("org_user").Where(cond) 38 + } 39 + 40 + func (opts FindOrgOptions) ToConds() builder.Cond { 41 + var cond builder.Cond = builder.Eq{"`user`.`type`": user_model.UserTypeOrganization} 42 + if opts.UserID > 0 { 43 + cond = cond.And(builder.In("`user`.`id`", queryUserOrgIDs(opts.UserID, opts.IncludePrivate))) 44 + } 45 + if !opts.IncludePrivate { 46 + cond = cond.And(builder.Eq{"`user`.visibility": structs.VisibleTypePublic}) 47 + } 48 + return cond 49 + } 50 + 51 + func (opts FindOrgOptions) ToOrders() string { 52 + return "`user`.lower_name ASC" 53 + } 54 + 55 + // GetOrgsCanCreateRepoByUserID returns a list of organizations where given user ID 56 + // are allowed to create repos. 57 + func GetOrgsCanCreateRepoByUserID(ctx context.Context, userID int64) ([]*Organization, error) { 58 + orgs := make([]*Organization, 0, 10) 59 + 60 + return orgs, db.GetEngine(ctx).Where(builder.In("id", builder.Select("`user`.id").From("`user`"). 61 + Join("INNER", "`team_user`", "`team_user`.org_id = `user`.id"). 62 + Join("INNER", "`team`", "`team`.id = `team_user`.team_id"). 63 + Where(builder.Eq{"`team_user`.uid": userID}). 64 + And(builder.Eq{"`team`.authorize": perm.AccessModeOwner}.Or(builder.Eq{"`team`.can_create_org_repo": true})))). 65 + Asc("`user`.name"). 66 + Find(&orgs) 67 + } 68 + 69 + // MinimalOrg represents a simple organization with only the needed columns 70 + type MinimalOrg = Organization 71 + 72 + // GetUserOrgsList returns all organizations the given user has access to 73 + func GetUserOrgsList(ctx context.Context, user *user_model.User) ([]*MinimalOrg, error) { 74 + schema, err := db.TableInfo(new(user_model.User)) 75 + if err != nil { 76 + return nil, err 77 + } 78 + 79 + outputCols := []string{ 80 + "id", 81 + "name", 82 + "full_name", 83 + "visibility", 84 + "avatar", 85 + "avatar_email", 86 + "use_custom_avatar", 87 + } 88 + 89 + selectColumns := &strings.Builder{} 90 + for i, col := range outputCols { 91 + fmt.Fprintf(selectColumns, "`%s`.%s", schema.Name, col) 92 + if i < len(outputCols)-1 { 93 + selectColumns.WriteString(", ") 94 + } 95 + } 96 + columnsStr := selectColumns.String() 97 + 98 + var orgs []*MinimalOrg 99 + if err := db.GetEngine(ctx).Select(columnsStr). 100 + Table("user"). 101 + Where(builder.In("`user`.`id`", queryUserOrgIDs(user.ID, true))). 102 + Find(&orgs); err != nil { 103 + return nil, err 104 + } 105 + 106 + type orgCount struct { 107 + OrgID int64 108 + RepoCount int 109 + } 110 + var orgCounts []orgCount 111 + if err := db.GetEngine(ctx). 112 + Select("owner_id AS org_id, COUNT(DISTINCT(repository.id)) as repo_count"). 113 + Table("repository"). 114 + Join("INNER", "org_user", "owner_id = org_user.org_id"). 115 + Where("org_user.uid = ?", user.ID). 116 + And(builder.Or( 117 + builder.Eq{"repository.is_private": false}, 118 + builder.In("repository.id", builder.Select("repo_id").From("team_repo"). 119 + InnerJoin("team_user", "team_user.team_id = team_repo.team_id"). 120 + Where(builder.Eq{"team_user.uid": user.ID})), 121 + builder.In("repository.id", builder.Select("repo_id").From("collaboration"). 122 + Where(builder.Eq{"user_id": user.ID})), 123 + )). 124 + GroupBy("owner_id").Find(&orgCounts); err != nil { 125 + return nil, err 126 + } 127 + 128 + orgCountMap := make(map[int64]int, len(orgCounts)) 129 + for _, orgCount := range orgCounts { 130 + orgCountMap[orgCount.OrgID] = orgCount.RepoCount 131 + } 132 + 133 + for _, org := range orgs { 134 + org.NumRepos = orgCountMap[org.ID] 135 + } 136 + 137 + return orgs, nil 138 + }
+63
models/organization/org_list_test.go
··· 1 + // Copyright 2024 The Gitea Authors. All rights reserved. 2 + // SPDX-License-Identifier: MIT 3 + 4 + package organization_test 5 + 6 + import ( 7 + "testing" 8 + 9 + "code.gitea.io/gitea/models/db" 10 + "code.gitea.io/gitea/models/organization" 11 + "code.gitea.io/gitea/models/unittest" 12 + user_model "code.gitea.io/gitea/models/user" 13 + 14 + "github.com/stretchr/testify/assert" 15 + "github.com/stretchr/testify/require" 16 + ) 17 + 18 + func TestCountOrganizations(t *testing.T) { 19 + require.NoError(t, unittest.PrepareTestDatabase()) 20 + expected, err := db.GetEngine(db.DefaultContext).Where("type=?", user_model.UserTypeOrganization).Count(&organization.Organization{}) 21 + require.NoError(t, err) 22 + cnt, err := db.Count[organization.Organization](db.DefaultContext, organization.FindOrgOptions{IncludePrivate: true}) 23 + require.NoError(t, err) 24 + assert.Equal(t, expected, cnt) 25 + } 26 + 27 + func TestFindOrgs(t *testing.T) { 28 + require.NoError(t, unittest.PrepareTestDatabase()) 29 + 30 + orgs, err := db.Find[organization.Organization](db.DefaultContext, organization.FindOrgOptions{ 31 + UserID: 4, 32 + IncludePrivate: true, 33 + }) 34 + require.NoError(t, err) 35 + if assert.Len(t, orgs, 1) { 36 + assert.EqualValues(t, 3, orgs[0].ID) 37 + } 38 + 39 + orgs, err = db.Find[organization.Organization](db.DefaultContext, organization.FindOrgOptions{ 40 + UserID: 4, 41 + IncludePrivate: false, 42 + }) 43 + require.NoError(t, err) 44 + assert.Empty(t, orgs) 45 + 46 + total, err := db.Count[organization.Organization](db.DefaultContext, organization.FindOrgOptions{ 47 + UserID: 4, 48 + IncludePrivate: true, 49 + }) 50 + require.NoError(t, err) 51 + assert.EqualValues(t, 1, total) 52 + } 53 + 54 + func TestGetUserOrgsList(t *testing.T) { 55 + require.NoError(t, unittest.PrepareTestDatabase()) 56 + orgs, err := organization.GetUserOrgsList(db.DefaultContext, &user_model.User{ID: 4}) 57 + require.NoError(t, err) 58 + if assert.Len(t, orgs, 1) { 59 + assert.EqualValues(t, 3, orgs[0].ID) 60 + // repo_id: 3 is in the team, 32 is public, 5 is private with no team 61 + assert.EqualValues(t, 2, orgs[0].NumRepos) 62 + } 63 + }
+30 -60
models/organization/org_test.go
··· 4 4 package organization_test 5 5 6 6 import ( 7 + "sort" 7 8 "testing" 8 9 9 10 "code.gitea.io/gitea/models/db" ··· 104 105 func TestUser_GetMembers(t *testing.T) { 105 106 require.NoError(t, unittest.PrepareTestDatabase()) 106 107 org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) 107 - members, _, err := org.GetMembers(db.DefaultContext) 108 + members, _, err := org.GetMembers(db.DefaultContext, &user_model.User{IsAdmin: true}) 108 109 require.NoError(t, err) 109 110 if assert.Len(t, members, 3) { 110 111 assert.Equal(t, int64(2), members[0].ID) ··· 126 127 127 128 _, err = organization.GetOrgByName(db.DefaultContext, "") // corner case 128 129 assert.True(t, organization.IsErrOrgNotExist(err)) 129 - } 130 - 131 - func TestCountOrganizations(t *testing.T) { 132 - require.NoError(t, unittest.PrepareTestDatabase()) 133 - expected, err := db.GetEngine(db.DefaultContext).Where("type=?", user_model.UserTypeOrganization).Count(&organization.Organization{}) 134 - require.NoError(t, err) 135 - cnt, err := db.Count[organization.Organization](db.DefaultContext, organization.FindOrgOptions{IncludePrivate: true}) 136 - require.NoError(t, err) 137 - assert.Equal(t, expected, cnt) 138 130 } 139 131 140 132 func TestIsOrganizationOwner(t *testing.T) { ··· 181 173 test(unittest.NonexistentID, unittest.NonexistentID, false) 182 174 } 183 175 184 - func TestFindOrgs(t *testing.T) { 176 + func TestGetOrgUsersByOrgID(t *testing.T) { 185 177 require.NoError(t, unittest.PrepareTestDatabase()) 186 178 187 - orgs, err := db.Find[organization.Organization](db.DefaultContext, organization.FindOrgOptions{ 188 - UserID: 4, 189 - IncludePrivate: true, 190 - }) 191 - require.NoError(t, err) 192 - if assert.Len(t, orgs, 1) { 193 - assert.EqualValues(t, 3, orgs[0].ID) 179 + opts := &organization.FindOrgMembersOpts{ 180 + Doer: &user_model.User{IsAdmin: true}, 181 + OrgID: 3, 194 182 } 195 - 196 - orgs, err = db.Find[organization.Organization](db.DefaultContext, organization.FindOrgOptions{ 197 - UserID: 4, 198 - IncludePrivate: false, 199 - }) 183 + assert.False(t, opts.PublicOnly()) 184 + orgUsers, err := organization.GetOrgUsersByOrgID(db.DefaultContext, opts) 200 185 require.NoError(t, err) 201 - assert.Empty(t, orgs) 202 - 203 - total, err := db.Count[organization.Organization](db.DefaultContext, organization.FindOrgOptions{ 204 - UserID: 4, 205 - IncludePrivate: true, 186 + sort.Slice(orgUsers, func(i, j int) bool { 187 + return orgUsers[i].ID < orgUsers[j].ID 206 188 }) 207 - require.NoError(t, err) 208 - assert.EqualValues(t, 1, total) 209 - } 210 - 211 - func TestGetOrgUsersByOrgID(t *testing.T) { 212 - require.NoError(t, unittest.PrepareTestDatabase()) 189 + assert.EqualValues(t, []*organization.OrgUser{{ 190 + ID: 1, 191 + OrgID: 3, 192 + UID: 2, 193 + IsPublic: true, 194 + }, { 195 + ID: 2, 196 + OrgID: 3, 197 + UID: 4, 198 + IsPublic: false, 199 + }, { 200 + ID: 9, 201 + OrgID: 3, 202 + UID: 28, 203 + IsPublic: true, 204 + }}, orgUsers) 213 205 214 - orgUsers, err := organization.GetOrgUsersByOrgID(db.DefaultContext, &organization.FindOrgMembersOpts{ 215 - ListOptions: db.ListOptions{}, 216 - OrgID: 3, 217 - PublicOnly: false, 218 - }) 206 + opts = &organization.FindOrgMembersOpts{OrgID: 3} 207 + assert.True(t, opts.PublicOnly()) 208 + orgUsers, err = organization.GetOrgUsersByOrgID(db.DefaultContext, opts) 219 209 require.NoError(t, err) 220 - if assert.Len(t, orgUsers, 3) { 221 - assert.Equal(t, organization.OrgUser{ 222 - ID: orgUsers[0].ID, 223 - OrgID: 3, 224 - UID: 2, 225 - IsPublic: true, 226 - }, *orgUsers[0]) 227 - assert.Equal(t, organization.OrgUser{ 228 - ID: orgUsers[1].ID, 229 - OrgID: 3, 230 - UID: 4, 231 - IsPublic: false, 232 - }, *orgUsers[1]) 233 - assert.Equal(t, organization.OrgUser{ 234 - ID: orgUsers[2].ID, 235 - OrgID: 3, 236 - UID: 28, 237 - IsPublic: true, 238 - }, *orgUsers[2]) 239 - } 210 + assert.Len(t, orgUsers, 2) 240 211 241 212 orgUsers, err = organization.GetOrgUsersByOrgID(db.DefaultContext, &organization.FindOrgMembersOpts{ 242 213 ListOptions: db.ListOptions{}, 243 214 OrgID: unittest.NonexistentID, 244 - PublicOnly: false, 245 215 }) 246 216 require.NoError(t, err) 247 217 assert.Empty(t, orgUsers)
+2 -2
models/organization/org_user_test.go
··· 95 95 func testUserListIsPublicMember(t *testing.T, orgID int64, expected map[int64]bool) { 96 96 org, err := organization.GetOrgByID(db.DefaultContext, orgID) 97 97 require.NoError(t, err) 98 - _, membersIsPublic, err := org.GetMembers(db.DefaultContext) 98 + _, membersIsPublic, err := org.GetMembers(db.DefaultContext, &user_model.User{IsAdmin: true}) 99 99 require.NoError(t, err) 100 100 assert.Equal(t, expected, membersIsPublic) 101 101 } ··· 122 122 func testUserListIsUserOrgOwner(t *testing.T, orgID int64, expected map[int64]bool) { 123 123 org, err := organization.GetOrgByID(db.DefaultContext, orgID) 124 124 require.NoError(t, err) 125 - members, _, err := org.GetMembers(db.DefaultContext) 125 + members, _, err := org.GetMembers(db.DefaultContext, &user_model.User{IsAdmin: true}) 126 126 require.NoError(t, err) 127 127 assert.Equal(t, expected, organization.IsUserOrgOwner(db.DefaultContext, members, orgID)) 128 128 }
+4
models/project/project.go
··· 242 242 } 243 243 244 244 // NewProject creates a new Project 245 + // The title will be cut off at 255 characters if it's longer than 255 characters. 245 246 func NewProject(ctx context.Context, p *Project) error { 246 247 if !IsTemplateTypeValid(p.TemplateType) { 247 248 p.TemplateType = TemplateTypeNone ··· 254 255 if !IsTypeValid(p.Type) { 255 256 return util.NewInvalidArgumentErrorf("project type is not valid") 256 257 } 258 + 259 + p.Title, _ = util.SplitStringAtByteN(p.Title, 255) 257 260 258 261 return db.WithTx(ctx, func(ctx context.Context) error { 259 262 if err := db.Insert(ctx, p); err != nil { ··· 302 305 p.CardType = CardTypeTextOnly 303 306 } 304 307 308 + p.Title, _ = util.SplitStringAtByteN(p.Title, 255) 305 309 _, err := db.GetEngine(ctx).ID(p.ID).Cols( 306 310 "title", 307 311 "description",
+1
models/repo/release.go
··· 171 171 172 172 // UpdateRelease updates all columns of a release 173 173 func UpdateRelease(ctx context.Context, rel *Release) error { 174 + rel.Title, _ = util.SplitStringAtByteN(rel.Title, 255) 174 175 _, err := db.GetEngine(ctx).ID(rel.ID).AllCols().Update(rel) 175 176 return err 176 177 }
+1 -1
modules/markup/asciicast/asciicast.go
··· 39 39 // SanitizerRules implements markup.Renderer 40 40 func (Renderer) SanitizerRules() []setting.MarkupSanitizerRule { 41 41 return []setting.MarkupSanitizerRule{ 42 - {Element: "div", AllowAttr: "class", Regexp: regexp.MustCompile(playerClassName)}, 42 + {Element: "div", AllowAttr: "class", Regexp: regexp.MustCompile("^" + playerClassName + "$")}, 43 43 {Element: "div", AllowAttr: playerSrcAttr}, 44 44 } 45 45 }
+3 -3
modules/markup/csv/csv.go
··· 37 37 // SanitizerRules implements markup.Renderer 38 38 func (Renderer) SanitizerRules() []setting.MarkupSanitizerRule { 39 39 return []setting.MarkupSanitizerRule{ 40 - {Element: "table", AllowAttr: "class", Regexp: regexp.MustCompile(`data-table`)}, 41 - {Element: "th", AllowAttr: "class", Regexp: regexp.MustCompile(`line-num`)}, 42 - {Element: "td", AllowAttr: "class", Regexp: regexp.MustCompile(`line-num`)}, 40 + {Element: "table", AllowAttr: "class", Regexp: regexp.MustCompile(`^data-table$`)}, 41 + {Element: "th", AllowAttr: "class", Regexp: regexp.MustCompile(`^line-num$`)}, 42 + {Element: "td", AllowAttr: "class", Regexp: regexp.MustCompile(`^line-num$`)}, 43 43 } 44 44 } 45 45
+8
release-notes/5997.md
··· 1 + fix(security): [commit](https://codeberg.org/forgejo/forgejo/commit/45435a8789f8ff69603799a9031246d2d621d139) Fix and refactor markdown rendering 2 + fix: [commit](https://codeberg.org/forgejo/forgejo/commit/a8f2002a9b061ec1092df67c6f05e30aa7d2e2d2) Remove transaction for archive download 3 + fix: [commit](https://codeberg.org/forgejo/forgejo/commit/96ee0f56475204b2bbdc7f2aeb35b1c32eac469c) Fix oauth2 error handle not return immediately 4 + fix: [commit](https://codeberg.org/forgejo/forgejo/commit/c2e8790df37a14b4d2f72c7377db75309e0ebf1d) Trim title before insert/update to database to match the size requirements of database 5 + fix: [commit](https://codeberg.org/forgejo/forgejo/commit/03ab73d92eabaf774278effe3332623b1dc3580a) Fix nil panic if repo doesn't exist 6 + fix: [commit](https://codeberg.org/forgejo/forgejo/commit/56971f9ed90a01fd74a634b7496593e6f62ac260) Disable Oauth check if oauth disabled 7 + fix: [commit](https://codeberg.org/forgejo/forgejo/commit/7f51210672031aee7a790455d51a17ce11a70559) Harden runner updateTask and updateLog api 8 + feat: [commit](https://codeberg.org/forgejo/forgejo/commit/dd3c4d7096cff91854bcc6641f55d9d093e5c86e) Add a doctor check to disable the "Actions" unit for mirrors
+7 -1
routers/api/actions/runner/runner.go
··· 177 177 ctx context.Context, 178 178 req *connect.Request[runnerv1.UpdateTaskRequest], 179 179 ) (*connect.Response[runnerv1.UpdateTaskResponse], error) { 180 - task, err := actions_model.UpdateTaskByState(ctx, req.Msg.State) 180 + runner := GetRunner(ctx) 181 + 182 + task, err := actions_model.UpdateTaskByState(ctx, runner.ID, req.Msg.State) 181 183 if err != nil { 182 184 return nil, status.Errorf(codes.Internal, "update task: %v", err) 183 185 } ··· 239 241 ctx context.Context, 240 242 req *connect.Request[runnerv1.UpdateLogRequest], 241 243 ) (*connect.Response[runnerv1.UpdateLogResponse], error) { 244 + runner := GetRunner(ctx) 245 + 242 246 res := connect.NewResponse(&runnerv1.UpdateLogResponse{}) 243 247 244 248 task, err := actions_model.GetTaskByID(ctx, req.Msg.TaskId) 245 249 if err != nil { 246 250 return nil, status.Errorf(codes.Internal, "get task: %v", err) 251 + } else if runner.ID != task.RunnerID { 252 + return nil, status.Errorf(codes.Internal, "invalid runner for task") 247 253 } 248 254 ack := task.LogLength 249 255
+13 -9
routers/api/v1/org/member.go
··· 18 18 ) 19 19 20 20 // listMembers list an organization's members 21 - func listMembers(ctx *context.APIContext, publicOnly bool) { 21 + func listMembers(ctx *context.APIContext, isMember bool) { 22 22 opts := &organization.FindOrgMembersOpts{ 23 - OrgID: ctx.Org.Organization.ID, 24 - PublicOnly: publicOnly, 25 - ListOptions: utils.GetListOptions(ctx), 23 + Doer: ctx.Doer, 24 + IsDoerMember: isMember, 25 + OrgID: ctx.Org.Organization.ID, 26 + ListOptions: utils.GetListOptions(ctx), 26 27 } 27 28 28 29 count, err := organization.CountOrgMembers(ctx, opts) ··· 73 74 // "404": 74 75 // "$ref": "#/responses/notFound" 75 76 76 - publicOnly := true 77 + var ( 78 + isMember bool 79 + err error 80 + ) 81 + 77 82 if ctx.Doer != nil { 78 - isMember, err := ctx.Org.Organization.IsOrgMember(ctx, ctx.Doer.ID) 83 + isMember, err = ctx.Org.Organization.IsOrgMember(ctx, ctx.Doer.ID) 79 84 if err != nil { 80 85 ctx.Error(http.StatusInternalServerError, "IsOrgMember", err) 81 86 return 82 87 } 83 - publicOnly = !isMember && !ctx.Doer.IsAdmin 84 88 } 85 - listMembers(ctx, publicOnly) 89 + listMembers(ctx, isMember) 86 90 } 87 91 88 92 // ListPublicMembers list an organization's public members ··· 112 116 // "404": 113 117 // "$ref": "#/responses/notFound" 114 118 115 - listMembers(ctx, true) 119 + listMembers(ctx, false) 116 120 } 117 121 118 122 // IsMember check if a user is a member of an organization
+2
routers/web/auth/oauth.go
··· 1013 1013 } 1014 1014 if err, ok := err.(*go_oauth2.RetrieveError); ok { 1015 1015 ctx.Flash.Error("OAuth2 RetrieveError: "+err.Error(), true) 1016 + ctx.Redirect(setting.AppSubURL + "/user/login") 1017 + return 1016 1018 } 1017 1019 ctx.ServerError("UserSignIn", err) 1018 1020 return
+5 -3
routers/web/org/home.go
··· 110 110 } 111 111 112 112 opts := &organization.FindOrgMembersOpts{ 113 - OrgID: org.ID, 114 - PublicOnly: ctx.Org.PublicMemberOnly, 115 - ListOptions: db.ListOptions{Page: 1, PageSize: 25}, 113 + Doer: ctx.Doer, 114 + OrgID: org.ID, 115 + IsDoerMember: ctx.Org.IsMember, 116 + ListOptions: db.ListOptions{Page: 1, PageSize: 25}, 116 117 } 118 + 117 119 members, _, err := organization.FindOrgMembers(ctx, opts) 118 120 if err != nil { 119 121 ctx.ServerError("FindOrgMembers", err)
+4 -4
routers/web/org/members.go
··· 33 33 } 34 34 35 35 opts := &organization.FindOrgMembersOpts{ 36 - OrgID: org.ID, 37 - PublicOnly: true, 36 + Doer: ctx.Doer, 37 + OrgID: org.ID, 38 38 } 39 39 40 40 if ctx.Doer != nil { ··· 43 43 ctx.Error(http.StatusInternalServerError, "IsOrgMember") 44 44 return 45 45 } 46 - opts.PublicOnly = !isMember && !ctx.Doer.IsAdmin 46 + opts.IsDoerMember = isMember 47 47 } 48 - ctx.Data["PublicOnly"] = opts.PublicOnly 48 + ctx.Data["PublicOnly"] = opts.PublicOnly() 49 49 50 50 total, err := organization.CountOrgMembers(ctx, opts) 51 51 if err != nil {
+37 -31
routers/web/web.go
··· 327 327 } 328 328 } 329 329 330 + oauth2Enabled := func(ctx *context.Context) { 331 + if !setting.OAuth2.Enabled { 332 + ctx.Error(http.StatusForbidden) 333 + return 334 + } 335 + } 336 + 330 337 reqMilestonesDashboardPageEnabled := func(ctx *context.Context) { 331 338 if !setting.Service.ShowMilestonesDashboardPage { 332 339 ctx.Error(http.StatusForbidden) ··· 516 523 m.Any("/user/events", routing.MarkLongPolling, events.Events) 517 524 518 525 m.Group("/login/oauth", func() { 519 - m.Get("/authorize", web.Bind(forms.AuthorizationForm{}), auth.AuthorizeOAuth) 520 - m.Post("/grant", web.Bind(forms.GrantApplicationForm{}), auth.GrantApplicationOAuth) 521 - // TODO manage redirection 522 - m.Post("/authorize", web.Bind(forms.AuthorizationForm{}), auth.AuthorizeOAuth) 523 - }, ignSignInAndCsrf, reqSignIn) 526 + m.Group("", func() { 527 + m.Get("/authorize", web.Bind(forms.AuthorizationForm{}), auth.AuthorizeOAuth) 528 + m.Post("/grant", web.Bind(forms.GrantApplicationForm{}), auth.GrantApplicationOAuth) 529 + // TODO manage redirection 530 + m.Post("/authorize", web.Bind(forms.AuthorizationForm{}), auth.AuthorizeOAuth) 531 + }, ignSignInAndCsrf, reqSignIn) 524 532 525 - m.Methods("GET, OPTIONS", "/login/oauth/userinfo", optionsCorsHandler(), ignSignInAndCsrf, auth.InfoOAuth) 526 - m.Methods("POST, OPTIONS", "/login/oauth/access_token", optionsCorsHandler(), web.Bind(forms.AccessTokenForm{}), ignSignInAndCsrf, auth.AccessTokenOAuth) 527 - m.Methods("GET, OPTIONS", "/login/oauth/keys", optionsCorsHandler(), ignSignInAndCsrf, auth.OIDCKeys) 528 - m.Methods("POST, OPTIONS", "/login/oauth/introspect", optionsCorsHandler(), web.Bind(forms.IntrospectTokenForm{}), ignSignInAndCsrf, auth.IntrospectOAuth) 533 + m.Methods("GET, OPTIONS", "/userinfo", optionsCorsHandler(), ignSignInAndCsrf, auth.InfoOAuth) 534 + m.Methods("POST, OPTIONS", "/access_token", optionsCorsHandler(), web.Bind(forms.AccessTokenForm{}), ignSignInAndCsrf, auth.AccessTokenOAuth) 535 + m.Methods("GET, OPTIONS", "/keys", optionsCorsHandler(), ignSignInAndCsrf, auth.OIDCKeys) 536 + m.Methods("POST, OPTIONS", "/introspect", optionsCorsHandler(), web.Bind(forms.IntrospectTokenForm{}), ignSignInAndCsrf, auth.IntrospectOAuth) 537 + }, oauth2Enabled) 529 538 530 539 m.Group("/user/settings", func() { 531 540 m.Get("", user_setting.Profile) ··· 567 576 }, openIDSignInEnabled) 568 577 m.Post("/account_link", linkAccountEnabled, security.DeleteAccountLink) 569 578 }) 570 - m.Group("/applications/oauth2", func() { 571 - m.Get("/{id}", user_setting.OAuth2ApplicationShow) 572 - m.Post("/{id}", web.Bind(forms.EditOAuth2ApplicationForm{}), user_setting.OAuthApplicationsEdit) 573 - m.Post("/{id}/regenerate_secret", user_setting.OAuthApplicationsRegenerateSecret) 574 - m.Post("", web.Bind(forms.EditOAuth2ApplicationForm{}), user_setting.OAuthApplicationsPost) 575 - m.Post("/{id}/delete", user_setting.DeleteOAuth2Application) 576 - m.Post("/{id}/revoke/{grantId}", user_setting.RevokeOAuth2Grant) 579 + 580 + m.Group("/applications", func() { 581 + // oauth2 applications 582 + m.Group("/oauth2", func() { 583 + m.Get("/{id}", user_setting.OAuth2ApplicationShow) 584 + m.Post("/{id}", web.Bind(forms.EditOAuth2ApplicationForm{}), user_setting.OAuthApplicationsEdit) 585 + m.Post("/{id}/regenerate_secret", user_setting.OAuthApplicationsRegenerateSecret) 586 + m.Post("", web.Bind(forms.EditOAuth2ApplicationForm{}), user_setting.OAuthApplicationsPost) 587 + m.Post("/{id}/delete", user_setting.DeleteOAuth2Application) 588 + m.Post("/{id}/revoke/{grantId}", user_setting.RevokeOAuth2Grant) 589 + }, oauth2Enabled) 590 + 591 + // access token applications 592 + m.Combo("").Get(user_setting.Applications). 593 + Post(web.Bind(forms.NewAccessTokenForm{}), user_setting.ApplicationsPost) 594 + m.Post("/delete", user_setting.DeleteApplication) 577 595 }) 578 - m.Combo("/applications").Get(user_setting.Applications). 579 - Post(web.Bind(forms.NewAccessTokenForm{}), user_setting.ApplicationsPost) 580 - m.Post("/applications/delete", user_setting.DeleteApplication) 596 + 581 597 m.Combo("/keys").Get(user_setting.Keys). 582 598 Post(web.Bind(forms.AddKeyForm{}), user_setting.KeysPost) 583 599 m.Post("/keys/delete", user_setting.DeleteKey) ··· 755 771 m.Post("/regenerate_secret", admin.ApplicationsRegenerateSecret) 756 772 m.Post("/delete", admin.DeleteApplication) 757 773 }) 758 - }, func(ctx *context.Context) { 759 - if !setting.OAuth2.Enabled { 760 - ctx.Error(http.StatusForbidden) 761 - return 762 - } 763 - }) 774 + }, oauth2Enabled) 764 775 765 776 m.Group("/actions", func() { 766 777 m.Get("", admin.RedirectToDefaultSetting) ··· 883 894 m.Post("/regenerate_secret", org.OAuthApplicationsRegenerateSecret) 884 895 m.Post("/delete", org.DeleteOAuth2Application) 885 896 }) 886 - }, func(ctx *context.Context) { 887 - if !setting.OAuth2.Enabled { 888 - ctx.Error(http.StatusForbidden) 889 - return 890 - } 891 - }) 897 + }, oauth2Enabled) 892 898 893 899 m.Group("/hooks", func() { 894 900 m.Get("", org.Webhooks)
+3
services/auth/oauth2.go
··· 68 68 // CheckOAuthAccessToken returns uid of user from oauth token 69 69 // + non default openid scopes requested 70 70 func CheckOAuthAccessToken(ctx context.Context, accessToken string) (int64, string) { 71 + if !setting.OAuth2.Enabled { 72 + return 0, "" 73 + } 71 74 // JWT tokens require a "." 72 75 if !strings.Contains(accessToken, ".") { 73 76 return 0, ""
+3 -4
services/context/org.go
··· 26 26 Organization *organization.Organization 27 27 OrgLink string 28 28 CanCreateOrgRepo bool 29 - PublicMemberOnly bool // Only display public members 30 29 31 30 Team *organization.Team 32 31 Teams []*organization.Team ··· 176 175 ctx.Data["OrgLink"] = ctx.Org.OrgLink 177 176 178 177 // Member 179 - ctx.Org.PublicMemberOnly = ctx.Doer == nil || !ctx.Org.IsMember && !ctx.Doer.IsAdmin 180 178 opts := &organization.FindOrgMembersOpts{ 181 - OrgID: org.ID, 182 - PublicOnly: ctx.Org.PublicMemberOnly, 179 + Doer: ctx.Doer, 180 + OrgID: org.ID, 181 + IsDoerMember: ctx.Org.IsMember, 183 182 } 184 183 ctx.Data["NumMembers"], err = organization.CountOrgMembers(ctx, opts) 185 184 if err != nil {
+70
services/doctor/actions.go
··· 1 + // Copyright 2024 The Gitea Authors. All rights reserved. 2 + // SPDX-License-Identifier: MIT 3 + 4 + package doctor 5 + 6 + import ( 7 + "context" 8 + "fmt" 9 + 10 + "code.gitea.io/gitea/models/db" 11 + repo_model "code.gitea.io/gitea/models/repo" 12 + unit_model "code.gitea.io/gitea/models/unit" 13 + "code.gitea.io/gitea/modules/log" 14 + "code.gitea.io/gitea/modules/optional" 15 + repo_service "code.gitea.io/gitea/services/repository" 16 + ) 17 + 18 + func disableMirrorActionsUnit(ctx context.Context, logger log.Logger, autofix bool) error { 19 + var reposToFix []*repo_model.Repository 20 + 21 + for page := 1; ; page++ { 22 + repos, _, err := repo_model.SearchRepository(ctx, &repo_model.SearchRepoOptions{ 23 + ListOptions: db.ListOptions{ 24 + PageSize: repo_model.RepositoryListDefaultPageSize, 25 + Page: page, 26 + }, 27 + Mirror: optional.Some(true), 28 + }) 29 + if err != nil { 30 + return fmt.Errorf("SearchRepository: %w", err) 31 + } 32 + if len(repos) == 0 { 33 + break 34 + } 35 + 36 + for _, repo := range repos { 37 + if repo.UnitEnabled(ctx, unit_model.TypeActions) { 38 + reposToFix = append(reposToFix, repo) 39 + } 40 + } 41 + } 42 + 43 + if len(reposToFix) == 0 { 44 + logger.Info("Found no mirror with actions unit enabled") 45 + } else { 46 + logger.Warn("Found %d mirrors with actions unit enabled", len(reposToFix)) 47 + } 48 + if !autofix || len(reposToFix) == 0 { 49 + return nil 50 + } 51 + 52 + for _, repo := range reposToFix { 53 + if err := repo_service.UpdateRepositoryUnits(ctx, repo, nil, []unit_model.Type{unit_model.TypeActions}); err != nil { 54 + return err 55 + } 56 + } 57 + logger.Info("Fixed %d mirrors with actions unit enabled", len(reposToFix)) 58 + 59 + return nil 60 + } 61 + 62 + func init() { 63 + Register(&Check{ 64 + Title: "Disable the actions unit for all mirrors", 65 + Name: "disable-mirror-actions-unit", 66 + IsDefault: false, 67 + Run: disableMirrorActionsUnit, 68 + Priority: 9, 69 + }) 70 + }
+1
services/release/release.go
··· 151 151 return err 152 152 } 153 153 154 + rel.Title, _ = util.SplitStringAtByteN(rel.Title, 255) 154 155 rel.LowerTagName = strings.ToLower(rel.TagName) 155 156 if err = db.Insert(gitRepo.Ctx, rel); err != nil { 156 157 return err
+13 -20
services/repository/archiver/archiver.go
··· 69 69 } 70 70 71 71 // NewRequest creates an archival request, based on the URI. The 72 - // resulting ArchiveRequest is suitable for being passed to ArchiveRepository() 72 + // resulting ArchiveRequest is suitable for being passed to Await() 73 73 // if it's determined that the request still needs to be satisfied. 74 74 func NewRequest(ctx context.Context, repoID int64, repo *git.Repository, uri string) (*ArchiveRequest, error) { 75 75 r := &ArchiveRequest{ ··· 168 168 } 169 169 } 170 170 171 + // doArchive satisfies the ArchiveRequest being passed in. Processing 172 + // will occur in a separate goroutine, as this phase may take a while to 173 + // complete. If the archive already exists, doArchive will not do 174 + // anything. In all cases, the caller should be examining the *ArchiveRequest 175 + // being returned for completion, as it may be different than the one they passed 176 + // in. 171 177 func doArchive(ctx context.Context, r *ArchiveRequest) (*repo_model.RepoArchiver, error) { 172 - txCtx, committer, err := db.TxContext(ctx) 173 - if err != nil { 174 - return nil, err 175 - } 176 - defer committer.Close() 177 - ctx, _, finished := process.GetManager().AddContext(txCtx, fmt.Sprintf("ArchiveRequest[%d]: %s", r.RepoID, r.GetArchiveName())) 178 + ctx, _, finished := process.GetManager().AddContext(ctx, fmt.Sprintf("ArchiveRequest[%d]: %s", r.RepoID, r.GetArchiveName())) 178 179 defer finished() 179 180 180 181 archiver, err := repo_model.GetRepoArchiver(ctx, r.RepoID, r.Type, r.CommitID) ··· 209 210 return nil, err 210 211 } 211 212 } 212 - return archiver, committer.Commit() 213 + return archiver, nil 213 214 } 214 215 215 216 if !errors.Is(err, os.ErrNotExist) { ··· 278 279 } 279 280 } 280 281 281 - return archiver, committer.Commit() 282 - } 283 - 284 - // ArchiveRepository satisfies the ArchiveRequest being passed in. Processing 285 - // will occur in a separate goroutine, as this phase may take a while to 286 - // complete. If the archive already exists, ArchiveRepository will not do 287 - // anything. In all cases, the caller should be examining the *ArchiveRequest 288 - // being returned for completion, as it may be different than the one they passed 289 - // in. 290 - func ArchiveRepository(ctx context.Context, request *ArchiveRequest) (*repo_model.RepoArchiver, error) { 291 - return doArchive(ctx, request) 282 + return archiver, nil 292 283 } 293 284 294 285 var archiverQueue *queue.WorkerPoolQueue[*ArchiveRequest] ··· 298 289 handler := func(items ...*ArchiveRequest) []*ArchiveRequest { 299 290 for _, archiveReq := range items { 300 291 log.Trace("ArchiverData Process: %#v", archiveReq) 301 - if _, err := doArchive(ctx, archiveReq); err != nil { 292 + if archiver, err := doArchive(ctx, archiveReq); err != nil { 302 293 log.Error("Archive %v failed: %v", archiveReq, err) 294 + } else { 295 + log.Trace("ArchiverData Success: %#v", archiver) 303 296 } 304 297 } 305 298 return nil
+6 -6
services/repository/archiver/archiver_test.go
··· 81 81 inFlight[1] = tgzReq 82 82 inFlight[2] = secondReq 83 83 84 - ArchiveRepository(db.DefaultContext, zipReq) 85 - ArchiveRepository(db.DefaultContext, tgzReq) 86 - ArchiveRepository(db.DefaultContext, secondReq) 84 + doArchive(db.DefaultContext, zipReq) 85 + doArchive(db.DefaultContext, tgzReq) 86 + doArchive(db.DefaultContext, secondReq) 87 87 88 88 // Make sure sending an unprocessed request through doesn't affect the queue 89 89 // count. 90 - ArchiveRepository(db.DefaultContext, zipReq) 90 + doArchive(db.DefaultContext, zipReq) 91 91 92 92 // Sleep two seconds to make sure the queue doesn't change. 93 93 time.Sleep(2 * time.Second) ··· 102 102 // We still have the other three stalled at completion, waiting to remove 103 103 // from archiveInProgress. Try to submit this new one before its 104 104 // predecessor has cleared out of the queue. 105 - ArchiveRepository(db.DefaultContext, zipReq2) 105 + doArchive(db.DefaultContext, zipReq2) 106 106 107 107 // Now we'll submit a request and TimedWaitForCompletion twice, before and 108 108 // after we release it. We should trigger both the timeout and non-timeout ··· 110 110 timedReq, err := NewRequest(ctx, ctx.Repo.Repository.ID, ctx.Repo.GitRepo, secondCommit+".tar.gz") 111 111 require.NoError(t, err) 112 112 assert.NotNil(t, timedReq) 113 - ArchiveRepository(db.DefaultContext, timedReq) 113 + doArchive(db.DefaultContext, timedReq) 114 114 115 115 zipReq2, err = NewRequest(ctx, ctx.Repo.Repository.ID, ctx.Repo.GitRepo, firstCommit+".zip") 116 116 require.NoError(t, err)
+3 -2
tests/integration/user_count_test.go
··· 75 75 require.NoError(t, err) 76 76 77 77 countTest.memberCount, err = organization.CountOrgMembers(db.DefaultContext, &organization.FindOrgMembersOpts{ 78 - OrgID: org.ID, 79 - PublicOnly: !isMember, 78 + Doer: countTest.doer, 79 + OrgID: org.ID, 80 + IsDoerMember: isMember, 80 81 }) 81 82 require.NoError(t, err) 82 83