Skip to content

Commit 491c3cb

Browse files
authored
Merge branch 'main' into action-badge-layout
2 parents 0320018 + 0d2607a commit 491c3cb

File tree

44 files changed

+1505
-1010
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

+1505
-1010
lines changed

models/actions/run_job.go

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"time"
1111

1212
"code.gitea.io/gitea/models/db"
13+
repo_model "code.gitea.io/gitea/models/repo"
1314
"code.gitea.io/gitea/modules/timeutil"
1415
"code.gitea.io/gitea/modules/util"
1516

@@ -19,11 +20,12 @@ import (
1920
// ActionRunJob represents a job of a run
2021
type ActionRunJob struct {
2122
ID int64
22-
RunID int64 `xorm:"index"`
23-
Run *ActionRun `xorm:"-"`
24-
RepoID int64 `xorm:"index"`
25-
OwnerID int64 `xorm:"index"`
26-
CommitSHA string `xorm:"index"`
23+
RunID int64 `xorm:"index"`
24+
Run *ActionRun `xorm:"-"`
25+
RepoID int64 `xorm:"index"`
26+
Repo *repo_model.Repository `xorm:"-"`
27+
OwnerID int64 `xorm:"index"`
28+
CommitSHA string `xorm:"index"`
2729
IsForkPullRequest bool
2830
Name string `xorm:"VARCHAR(255)"`
2931
Attempt int64
@@ -58,6 +60,17 @@ func (job *ActionRunJob) LoadRun(ctx context.Context) error {
5860
return nil
5961
}
6062

63+
func (job *ActionRunJob) LoadRepo(ctx context.Context) error {
64+
if job.Repo == nil {
65+
repo, err := repo_model.GetRepositoryByID(ctx, job.RepoID)
66+
if err != nil {
67+
return err
68+
}
69+
job.Repo = repo
70+
}
71+
return nil
72+
}
73+
6174
// LoadAttributes load Run if not loaded
6275
func (job *ActionRunJob) LoadAttributes(ctx context.Context) error {
6376
if job == nil {
@@ -83,7 +96,7 @@ func GetRunJobByID(ctx context.Context, id int64) (*ActionRunJob, error) {
8396
return &job, nil
8497
}
8598

86-
func GetRunJobsByRunID(ctx context.Context, runID int64) ([]*ActionRunJob, error) {
99+
func GetRunJobsByRunID(ctx context.Context, runID int64) (ActionJobList, error) {
87100
var jobs []*ActionRunJob
88101
if err := db.GetEngine(ctx).Where("run_id=?", runID).OrderBy("id").Find(&jobs); err != nil {
89102
return nil, err

models/actions/run_job_list.go

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"context"
88

99
"code.gitea.io/gitea/models/db"
10+
repo_model "code.gitea.io/gitea/models/repo"
1011
"code.gitea.io/gitea/modules/container"
1112
"code.gitea.io/gitea/modules/timeutil"
1213

@@ -21,7 +22,33 @@ func (jobs ActionJobList) GetRunIDs() []int64 {
2122
})
2223
}
2324

25+
func (jobs ActionJobList) LoadRepos(ctx context.Context) error {
26+
repoIDs := container.FilterSlice(jobs, func(j *ActionRunJob) (int64, bool) {
27+
return j.RepoID, j.RepoID != 0 && j.Repo == nil
28+
})
29+
if len(repoIDs) == 0 {
30+
return nil
31+
}
32+
33+
repos := make(map[int64]*repo_model.Repository, len(repoIDs))
34+
if err := db.GetEngine(ctx).In("id", repoIDs).Find(&repos); err != nil {
35+
return err
36+
}
37+
for _, j := range jobs {
38+
if j.RepoID > 0 && j.Repo == nil {
39+
j.Repo = repos[j.RepoID]
40+
}
41+
}
42+
return nil
43+
}
44+
2445
func (jobs ActionJobList) LoadRuns(ctx context.Context, withRepo bool) error {
46+
if withRepo {
47+
if err := jobs.LoadRepos(ctx); err != nil {
48+
return err
49+
}
50+
}
51+
2552
runIDs := jobs.GetRunIDs()
2653
runs := make(map[int64]*ActionRun, len(runIDs))
2754
if err := db.GetEngine(ctx).In("id", runIDs).Find(&runs); err != nil {
@@ -30,15 +57,9 @@ func (jobs ActionJobList) LoadRuns(ctx context.Context, withRepo bool) error {
3057
for _, j := range jobs {
3158
if j.RunID > 0 && j.Run == nil {
3259
j.Run = runs[j.RunID]
60+
j.Run.Repo = j.Repo
3361
}
3462
}
35-
if withRepo {
36-
var runsList RunList = make([]*ActionRun, 0, len(runs))
37-
for _, r := range runs {
38-
runsList = append(runsList, r)
39-
}
40-
return runsList.LoadRepos(ctx)
41-
}
4263
return nil
4364
}
4465

models/migrations/migrations.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,7 @@ func prepareMigrationTasks() []*migration {
378378
newMigration(315, "Add Ephemeral to ActionRunner", v1_24.AddEphemeralToActionRunner),
379379
newMigration(316, "Add description for secrets and variables", v1_24.AddDescriptionForSecretsAndVariables),
380380
newMigration(317, "Add new index for action for heatmap", v1_24.AddNewIndexForUserDashboard),
381+
newMigration(318, "Add anonymous_access_mode for repo_unit", v1_24.AddRepoUnitAnonymousAccessMode),
381382
}
382383
return preparedMigrations
383384
}

models/migrations/v1_24/v318.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2025 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package v1_24 //nolint
5+
6+
import (
7+
"code.gitea.io/gitea/models/perm"
8+
9+
"xorm.io/xorm"
10+
)
11+
12+
func AddRepoUnitAnonymousAccessMode(x *xorm.Engine) error {
13+
type RepoUnit struct { //revive:disable-line:exported
14+
AnonymousAccessMode perm.AccessMode `xorm:"NOT NULL DEFAULT 0"`
15+
}
16+
return x.Sync(&RepoUnit{})
17+
}

models/perm/access/repo_permission.go

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ type Permission struct {
2525
units []*repo_model.RepoUnit
2626
unitsMode map[unit.Type]perm_model.AccessMode
2727

28-
everyoneAccessMode map[unit.Type]perm_model.AccessMode
28+
everyoneAccessMode map[unit.Type]perm_model.AccessMode // the unit's minimal access mode for every signed-in user
29+
anonymousAccessMode map[unit.Type]perm_model.AccessMode // the unit's minimal access mode for anonymous (non-signed-in) user
2930
}
3031

3132
// IsOwner returns true if current user is the owner of repository.
@@ -39,7 +40,7 @@ func (p *Permission) IsAdmin() bool {
3940
}
4041

4142
// HasAnyUnitAccess returns true if the user might have at least one access mode to any unit of this repository.
42-
// It doesn't count the "everyone access mode".
43+
// It doesn't count the "public(anonymous/everyone) access mode".
4344
func (p *Permission) HasAnyUnitAccess() bool {
4445
for _, v := range p.unitsMode {
4546
if v >= perm_model.AccessModeRead {
@@ -49,7 +50,12 @@ func (p *Permission) HasAnyUnitAccess() bool {
4950
return p.AccessMode >= perm_model.AccessModeRead
5051
}
5152

52-
func (p *Permission) HasAnyUnitAccessOrEveryoneAccess() bool {
53+
func (p *Permission) HasAnyUnitAccessOrPublicAccess() bool {
54+
for _, v := range p.anonymousAccessMode {
55+
if v >= perm_model.AccessModeRead {
56+
return true
57+
}
58+
}
5359
for _, v := range p.everyoneAccessMode {
5460
if v >= perm_model.AccessModeRead {
5561
return true
@@ -73,14 +79,16 @@ func (p *Permission) GetFirstUnitRepoID() int64 {
7379
}
7480

7581
// UnitAccessMode returns current user access mode to the specify unit of the repository
76-
// It also considers "everyone access mode"
82+
// It also considers "public (anonymous/everyone) access mode"
7783
func (p *Permission) UnitAccessMode(unitType unit.Type) perm_model.AccessMode {
7884
// if the units map contains the access mode, use it, but admin/owner mode could override it
7985
if m, ok := p.unitsMode[unitType]; ok {
8086
return util.Iif(p.AccessMode >= perm_model.AccessModeAdmin, p.AccessMode, m)
8187
}
8288
// if the units map does not contain the access mode, return the default access mode if the unit exists
83-
unitDefaultAccessMode := max(p.AccessMode, p.everyoneAccessMode[unitType])
89+
unitDefaultAccessMode := p.AccessMode
90+
unitDefaultAccessMode = max(unitDefaultAccessMode, p.anonymousAccessMode[unitType])
91+
unitDefaultAccessMode = max(unitDefaultAccessMode, p.everyoneAccessMode[unitType])
8492
hasUnit := slices.ContainsFunc(p.units, func(u *repo_model.RepoUnit) bool { return u.Type == unitType })
8593
return util.Iif(hasUnit, unitDefaultAccessMode, perm_model.AccessModeNone)
8694
}
@@ -171,27 +179,38 @@ func (p *Permission) LogString() string {
171179
format += "\n\tunitsMode[%-v]: %-v"
172180
args = append(args, key.LogString(), value.LogString())
173181
}
182+
format += "\n\tanonymousAccessMode: %-v"
183+
args = append(args, p.anonymousAccessMode)
174184
format += "\n\teveryoneAccessMode: %-v"
175185
args = append(args, p.everyoneAccessMode)
176186
format += "\n\t]>"
177187
return fmt.Sprintf(format, args...)
178188
}
179189

190+
func applyPublicAccessPermission(unitType unit.Type, accessMode perm_model.AccessMode, modeMap *map[unit.Type]perm_model.AccessMode) {
191+
if accessMode >= perm_model.AccessModeRead && accessMode > (*modeMap)[unitType] {
192+
if *modeMap == nil {
193+
*modeMap = make(map[unit.Type]perm_model.AccessMode)
194+
}
195+
(*modeMap)[unitType] = accessMode
196+
}
197+
}
198+
180199
func finalProcessRepoUnitPermission(user *user_model.User, perm *Permission) {
200+
// apply public (anonymous) access permissions
201+
for _, u := range perm.units {
202+
applyPublicAccessPermission(u.Type, u.AnonymousAccessMode, &perm.anonymousAccessMode)
203+
}
204+
181205
if user == nil || user.ID <= 0 {
182206
// for anonymous access, it could be:
183207
// AccessMode is None or Read, units has repo units, unitModes is nil
184208
return
185209
}
186210

187-
// apply everyone access permissions
211+
// apply public (everyone) access permissions
188212
for _, u := range perm.units {
189-
if u.EveryoneAccessMode >= perm_model.AccessModeRead && u.EveryoneAccessMode > perm.everyoneAccessMode[u.Type] {
190-
if perm.everyoneAccessMode == nil {
191-
perm.everyoneAccessMode = make(map[unit.Type]perm_model.AccessMode)
192-
}
193-
perm.everyoneAccessMode[u.Type] = u.EveryoneAccessMode
194-
}
213+
applyPublicAccessPermission(u.Type, u.EveryoneAccessMode, &perm.everyoneAccessMode)
195214
}
196215

197216
if perm.unitsMode == nil {
@@ -209,6 +228,11 @@ func finalProcessRepoUnitPermission(user *user_model.User, perm *Permission) {
209228
break
210229
}
211230
}
231+
for t := range perm.anonymousAccessMode {
232+
if shouldKeep = shouldKeep || u.Type == t; shouldKeep {
233+
break
234+
}
235+
}
212236
for t := range perm.everyoneAccessMode {
213237
if shouldKeep = shouldKeep || u.Type == t; shouldKeep {
214238
break

models/perm/access/repo_permission_test.go

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,21 @@ func TestHasAnyUnitAccess(t *testing.T) {
2222
units: []*repo_model.RepoUnit{{Type: unit.TypeWiki}},
2323
}
2424
assert.False(t, perm.HasAnyUnitAccess())
25-
assert.False(t, perm.HasAnyUnitAccessOrEveryoneAccess())
25+
assert.False(t, perm.HasAnyUnitAccessOrPublicAccess())
2626

2727
perm = Permission{
2828
units: []*repo_model.RepoUnit{{Type: unit.TypeWiki}},
2929
everyoneAccessMode: map[unit.Type]perm_model.AccessMode{unit.TypeIssues: perm_model.AccessModeRead},
3030
}
3131
assert.False(t, perm.HasAnyUnitAccess())
32-
assert.True(t, perm.HasAnyUnitAccessOrEveryoneAccess())
32+
assert.True(t, perm.HasAnyUnitAccessOrPublicAccess())
33+
34+
perm = Permission{
35+
units: []*repo_model.RepoUnit{{Type: unit.TypeWiki}},
36+
anonymousAccessMode: map[unit.Type]perm_model.AccessMode{unit.TypeIssues: perm_model.AccessModeRead},
37+
}
38+
assert.False(t, perm.HasAnyUnitAccess())
39+
assert.True(t, perm.HasAnyUnitAccessOrPublicAccess())
3340

3441
perm = Permission{
3542
AccessMode: perm_model.AccessModeRead,
@@ -43,7 +50,7 @@ func TestHasAnyUnitAccess(t *testing.T) {
4350
assert.True(t, perm.HasAnyUnitAccess())
4451
}
4552

46-
func TestApplyEveryoneRepoPermission(t *testing.T) {
53+
func TestApplyPublicAccessRepoPermission(t *testing.T) {
4754
perm := Permission{
4855
AccessMode: perm_model.AccessModeNone,
4956
units: []*repo_model.RepoUnit{
@@ -53,6 +60,15 @@ func TestApplyEveryoneRepoPermission(t *testing.T) {
5360
finalProcessRepoUnitPermission(nil, &perm)
5461
assert.False(t, perm.CanRead(unit.TypeWiki))
5562

63+
perm = Permission{
64+
AccessMode: perm_model.AccessModeNone,
65+
units: []*repo_model.RepoUnit{
66+
{Type: unit.TypeWiki, AnonymousAccessMode: perm_model.AccessModeRead},
67+
},
68+
}
69+
finalProcessRepoUnitPermission(nil, &perm)
70+
assert.True(t, perm.CanRead(unit.TypeWiki))
71+
5672
perm = Permission{
5773
AccessMode: perm_model.AccessModeNone,
5874
units: []*repo_model.RepoUnit{

models/repo/repo_unit.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,13 @@ func (err ErrUnitTypeNotExist) Unwrap() error {
4242

4343
// RepoUnit describes all units of a repository
4444
type RepoUnit struct { //revive:disable-line:exported
45-
ID int64
46-
RepoID int64 `xorm:"INDEX(s)"`
47-
Type unit.Type `xorm:"INDEX(s)"`
48-
Config convert.Conversion `xorm:"TEXT"`
49-
CreatedUnix timeutil.TimeStamp `xorm:"INDEX CREATED"`
50-
EveryoneAccessMode perm.AccessMode `xorm:"NOT NULL DEFAULT 0"`
45+
ID int64
46+
RepoID int64 `xorm:"INDEX(s)"`
47+
Type unit.Type `xorm:"INDEX(s)"`
48+
Config convert.Conversion `xorm:"TEXT"`
49+
CreatedUnix timeutil.TimeStamp `xorm:"INDEX CREATED"`
50+
AnonymousAccessMode perm.AccessMode `xorm:"NOT NULL DEFAULT 0"`
51+
EveryoneAccessMode perm.AccessMode `xorm:"NOT NULL DEFAULT 0"`
5152
}
5253

5354
func init() {

modules/git/batch.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,26 @@ type Batch struct {
1414
Writer WriteCloserError
1515
}
1616

17-
func (repo *Repository) NewBatch(ctx context.Context) (*Batch, error) {
17+
// NewBatch creates a new batch for the given repository, the Close must be invoked before release the batch
18+
func NewBatch(ctx context.Context, repoPath string) (*Batch, error) {
1819
// Now because of some insanity with git cat-file not immediately failing if not run in a valid git directory we need to run git rev-parse first!
19-
if err := ensureValidGitRepository(ctx, repo.Path); err != nil {
20+
if err := ensureValidGitRepository(ctx, repoPath); err != nil {
2021
return nil, err
2122
}
2223

2324
var batch Batch
24-
batch.Writer, batch.Reader, batch.cancel = catFileBatch(ctx, repo.Path)
25+
batch.Writer, batch.Reader, batch.cancel = catFileBatch(ctx, repoPath)
2526
return &batch, nil
2627
}
2728

28-
func (repo *Repository) NewBatchCheck(ctx context.Context) (*Batch, error) {
29+
func NewBatchCheck(ctx context.Context, repoPath string) (*Batch, error) {
2930
// Now because of some insanity with git cat-file not immediately failing if not run in a valid git directory we need to run git rev-parse first!
30-
if err := ensureValidGitRepository(ctx, repo.Path); err != nil {
31+
if err := ensureValidGitRepository(ctx, repoPath); err != nil {
3132
return nil, err
3233
}
3334

3435
var check Batch
35-
check.Writer, check.Reader, check.cancel = catFileBatchCheck(ctx, repo.Path)
36+
check.Writer, check.Reader, check.cancel = catFileBatchCheck(ctx, repoPath)
3637
return &check, nil
3738
}
3839

modules/git/command.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -350,9 +350,10 @@ func (c *Command) run(ctx context.Context, skip int, opts *RunOpts) error {
350350
// We need to check if the context is canceled by the program on Windows.
351351
// This is because Windows does not have signal checking when terminating the process.
352352
// It always returns exit code 1, unlike Linux, which has many exit codes for signals.
353+
// `err.Error()` returns "exit status 1" when using the `git check-attr` command after the context is canceled.
353354
if runtime.GOOS == "windows" &&
354355
err != nil &&
355-
err.Error() == "" &&
356+
(err.Error() == "" || err.Error() == "exit status 1") &&
356357
cmd.ProcessState.ExitCode() == 1 &&
357358
ctx.Err() == context.Canceled {
358359
return ctx.Err()

modules/git/repo_attribute.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ func (wr *nulSeparatedAttributeWriter) Write(p []byte) (n int, err error) {
280280
}
281281
}
282282
wr.tmp = append(wr.tmp, p...)
283-
return len(p), nil
283+
return l, nil
284284
}
285285

286286
func (wr *nulSeparatedAttributeWriter) ReadAttribute() <-chan attributeTriple {

0 commit comments

Comments
 (0)