Skip to content

Commit 0958343

Browse files
committed
Merge remote-tracking branch 'giteaofficial/main'
* giteaofficial/main: Refactor Branch struct in package modules/git (go-gitea#33980) Support creating relative link to raw path in markdown (go-gitea#34105) Add new CLI flags to set name and scopes when creating a user with access token (go-gitea#34080) Do not show 500 error when default branch doesn't exist (go-gitea#34096) Return default avatar url when user id is zero rather than updating database (go-gitea#34094) [skip ci] Updated translations via Crowdin Fix return bug (go-gitea#34093) Move ParseCommitWithSSHSignature to service layer (go-gitea#34087) fix(i18n): clarify ownership in password change error messages (go-gitea#34092) Enable addtional linters (go-gitea#34085) Add flat-square action badge style (go-gitea#34062) Fix some UI bugs and clean up unused tests (go-gitea#34088)
2 parents c480a69 + c27d87a commit 0958343

File tree

338 files changed

+1353
-1171
lines changed

Some content is hidden

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

338 files changed

+1353
-1171
lines changed

.golangci.yml

+3
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,17 @@ linters:
1313
- gocritic
1414
- govet
1515
- ineffassign
16+
- mirror
1617
- nakedret
1718
- nolintlint
19+
- perfsprint
1820
- revive
1921
- staticcheck
2022
- testifylint
2123
- unconvert
2224
- unparam
2325
- unused
26+
- usestdlibvars
2427
- usetesting
2528
- wastedassign
2629
settings:

cmd/admin_user_create.go

+37-9
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"context"
88
"errors"
99
"fmt"
10+
"strings"
1011

1112
auth_model "code.gitea.io/gitea/models/auth"
1213
"code.gitea.io/gitea/models/db"
@@ -66,6 +67,16 @@ var microcmdUserCreate = &cli.Command{
6667
Name: "access-token",
6768
Usage: "Generate access token for the user",
6869
},
70+
&cli.StringFlag{
71+
Name: "access-token-name",
72+
Usage: `Name of the generated access token`,
73+
Value: "gitea-admin",
74+
},
75+
&cli.StringFlag{
76+
Name: "access-token-scopes",
77+
Usage: `Scopes of the generated access token, comma separated. Examples: "all", "public-only,read:issue", "write:repository,write:user"`,
78+
Value: "all",
79+
},
6980
&cli.BoolFlag{
7081
Name: "restricted",
7182
Usage: "Make a restricted user account",
@@ -187,23 +198,40 @@ func runCreateUser(c *cli.Context) error {
187198
IsRestricted: restricted,
188199
}
189200

201+
var accessTokenName string
202+
var accessTokenScope auth_model.AccessTokenScope
203+
if c.IsSet("access-token") {
204+
accessTokenName = strings.TrimSpace(c.String("access-token-name"))
205+
if accessTokenName == "" {
206+
return errors.New("access-token-name cannot be empty")
207+
}
208+
var err error
209+
accessTokenScope, err = auth_model.AccessTokenScope(c.String("access-token-scopes")).Normalize()
210+
if err != nil {
211+
return fmt.Errorf("invalid access token scope provided: %w", err)
212+
}
213+
if !accessTokenScope.HasPermissionScope() {
214+
return errors.New("access token does not have any permission")
215+
}
216+
} else if c.IsSet("access-token-name") || c.IsSet("access-token-scopes") {
217+
return errors.New("access-token-name and access-token-scopes flags are only valid when access-token flag is set")
218+
}
219+
220+
// arguments should be prepared before creating the user & access token, in case there is anything wrong
221+
222+
// create the user
190223
if err := user_model.CreateUser(ctx, u, &user_model.Meta{}, overwriteDefault); err != nil {
191224
return fmt.Errorf("CreateUser: %w", err)
192225
}
226+
fmt.Printf("New user '%s' has been successfully created!\n", username)
193227

194-
if c.Bool("access-token") {
195-
t := &auth_model.AccessToken{
196-
Name: "gitea-admin",
197-
UID: u.ID,
198-
}
199-
228+
// create the access token
229+
if accessTokenScope != "" {
230+
t := &auth_model.AccessToken{Name: accessTokenName, UID: u.ID, Scope: accessTokenScope}
200231
if err := auth_model.NewAccessToken(ctx, t); err != nil {
201232
return err
202233
}
203-
204234
fmt.Printf("Access token was successfully created... %s\n", t.Token)
205235
}
206-
207-
fmt.Printf("New user '%s' has been successfully created!\n", username)
208236
return nil
209237
}

cmd/admin_user_create_test.go

+58-4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"strings"
99
"testing"
1010

11+
auth_model "code.gitea.io/gitea/models/auth"
1112
"code.gitea.io/gitea/models/db"
1213
"code.gitea.io/gitea/models/unittest"
1314
user_model "code.gitea.io/gitea/models/user"
@@ -22,6 +23,7 @@ func TestAdminUserCreate(t *testing.T) {
2223
reset := func() {
2324
require.NoError(t, db.TruncateBeans(db.DefaultContext, &user_model.User{}))
2425
require.NoError(t, db.TruncateBeans(db.DefaultContext, &user_model.EmailAddress{}))
26+
require.NoError(t, db.TruncateBeans(db.DefaultContext, &auth_model.AccessToken{}))
2527
}
2628

2729
t.Run("MustChangePassword", func(t *testing.T) {
@@ -48,11 +50,11 @@ func TestAdminUserCreate(t *testing.T) {
4850
assert.Equal(t, check{IsAdmin: false, MustChangePassword: false}, createCheck("u5", "--must-change-password=false"))
4951
})
5052

51-
t.Run("UserType", func(t *testing.T) {
52-
createUser := func(name, args string) error {
53-
return app.Run(strings.Fields(fmt.Sprintf("./gitea admin user create --username %s --email %[email protected] %s", name, name, args)))
54-
}
53+
createUser := func(name, args string) error {
54+
return app.Run(strings.Fields(fmt.Sprintf("./gitea admin user create --username %s --email %[email protected] %s", name, name, args)))
55+
}
5556

57+
t.Run("UserType", func(t *testing.T) {
5658
reset()
5759
assert.ErrorContains(t, createUser("u", "--user-type invalid"), "invalid user type")
5860
assert.ErrorContains(t, createUser("u", "--user-type bot --password 123"), "can only be set for individual users")
@@ -63,4 +65,56 @@ func TestAdminUserCreate(t *testing.T) {
6365
assert.Equal(t, user_model.UserTypeBot, u.Type)
6466
assert.Empty(t, u.Passwd)
6567
})
68+
69+
t.Run("AccessToken", func(t *testing.T) {
70+
// no generated access token
71+
reset()
72+
assert.NoError(t, createUser("u", "--random-password"))
73+
assert.Equal(t, 1, unittest.GetCount(t, &user_model.User{}))
74+
assert.Equal(t, 0, unittest.GetCount(t, &auth_model.AccessToken{}))
75+
76+
// using "--access-token" only means "all" access
77+
reset()
78+
assert.NoError(t, createUser("u", "--random-password --access-token"))
79+
assert.Equal(t, 1, unittest.GetCount(t, &user_model.User{}))
80+
assert.Equal(t, 1, unittest.GetCount(t, &auth_model.AccessToken{}))
81+
accessToken := unittest.AssertExistsAndLoadBean(t, &auth_model.AccessToken{Name: "gitea-admin"})
82+
hasScopes, err := accessToken.Scope.HasScope(auth_model.AccessTokenScopeWriteAdmin, auth_model.AccessTokenScopeWriteRepository)
83+
assert.NoError(t, err)
84+
assert.True(t, hasScopes)
85+
86+
// using "--access-token" with name & scopes
87+
reset()
88+
assert.NoError(t, createUser("u", "--random-password --access-token --access-token-name new-token-name --access-token-scopes read:issue,read:user"))
89+
assert.Equal(t, 1, unittest.GetCount(t, &user_model.User{}))
90+
assert.Equal(t, 1, unittest.GetCount(t, &auth_model.AccessToken{}))
91+
accessToken = unittest.AssertExistsAndLoadBean(t, &auth_model.AccessToken{Name: "new-token-name"})
92+
hasScopes, err = accessToken.Scope.HasScope(auth_model.AccessTokenScopeReadIssue, auth_model.AccessTokenScopeReadUser)
93+
assert.NoError(t, err)
94+
assert.True(t, hasScopes)
95+
hasScopes, err = accessToken.Scope.HasScope(auth_model.AccessTokenScopeWriteAdmin, auth_model.AccessTokenScopeWriteRepository)
96+
assert.NoError(t, err)
97+
assert.False(t, hasScopes)
98+
99+
// using "--access-token-name" without "--access-token"
100+
reset()
101+
err = createUser("u", "--random-password --access-token-name new-token-name")
102+
assert.Equal(t, 0, unittest.GetCount(t, &user_model.User{}))
103+
assert.Equal(t, 0, unittest.GetCount(t, &auth_model.AccessToken{}))
104+
assert.ErrorContains(t, err, "access-token-name and access-token-scopes flags are only valid when access-token flag is set")
105+
106+
// using "--access-token-scopes" without "--access-token"
107+
reset()
108+
err = createUser("u", "--random-password --access-token-scopes read:issue")
109+
assert.Equal(t, 0, unittest.GetCount(t, &user_model.User{}))
110+
assert.Equal(t, 0, unittest.GetCount(t, &auth_model.AccessToken{}))
111+
assert.ErrorContains(t, err, "access-token-name and access-token-scopes flags are only valid when access-token flag is set")
112+
113+
// empty permission
114+
reset()
115+
err = createUser("u", "--random-password --access-token --access-token-scopes public-only")
116+
assert.Equal(t, 0, unittest.GetCount(t, &user_model.User{}))
117+
assert.Equal(t, 0, unittest.GetCount(t, &auth_model.AccessToken{}))
118+
assert.ErrorContains(t, err, "access token does not have any permission")
119+
})
66120
}

cmd/admin_user_generate_access_token.go

+6-3
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,16 @@ var microcmdUserGenerateAccessToken = &cli.Command{
3434
},
3535
&cli.StringFlag{
3636
Name: "scopes",
37-
Value: "",
38-
Usage: "Comma separated list of scopes to apply to access token",
37+
Value: "all",
38+
Usage: `Comma separated list of scopes to apply to access token, examples: "all", "public-only,read:issue", "write:repository,write:user"`,
3939
},
4040
},
4141
Action: runGenerateAccessToken,
4242
}
4343

4444
func runGenerateAccessToken(c *cli.Context) error {
4545
if !c.IsSet("username") {
46-
return errors.New("You must provide a username to generate a token for")
46+
return errors.New("you must provide a username to generate a token for")
4747
}
4848

4949
ctx, cancel := installSignals()
@@ -77,6 +77,9 @@ func runGenerateAccessToken(c *cli.Context) error {
7777
if err != nil {
7878
return fmt.Errorf("invalid access token scope provided: %w", err)
7979
}
80+
if !accessTokenScope.HasPermissionScope() {
81+
return errors.New("access token does not have any permission")
82+
}
8083
t.Scope = accessTokenScope
8184

8285
// create the token

cmd/dump.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
package cmd
66

77
import (
8-
"fmt"
98
"os"
109
"path"
1110
"path/filepath"
@@ -93,7 +92,7 @@ var CmdDump = &cli.Command{
9392
},
9493
&cli.StringFlag{
9594
Name: "type",
96-
Usage: fmt.Sprintf(`Dump output format, default to "zip", supported types: %s`, strings.Join(dump.SupportedOutputTypes, ", ")),
95+
Usage: `Dump output format, default to "zip", supported types: ` + strings.Join(dump.SupportedOutputTypes, ", "),
9796
},
9897
},
9998
}

cmd/main_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package cmd
55

66
import (
7+
"errors"
78
"fmt"
89
"io"
910
"path/filepath"
@@ -127,7 +128,7 @@ func TestCliCmd(t *testing.T) {
127128
}
128129

129130
func TestCliCmdError(t *testing.T) {
130-
app := newTestApp(func(ctx *cli.Context) error { return fmt.Errorf("normal error") })
131+
app := newTestApp(func(ctx *cli.Context) error { return errors.New("normal error") })
131132
r, err := runTestApp(app, "./gitea", "test-cmd")
132133
assert.Error(t, err)
133134
assert.Equal(t, 1, r.ExitCode)

cmd/serv.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ func getLFSAuthToken(ctx context.Context, lfsVerb string, results *private.ServC
173173
if err != nil {
174174
return "", fail(ctx, "Failed to sign JWT Token", "Failed to sign JWT token: %v", err)
175175
}
176-
return fmt.Sprintf("Bearer %s", tokenString), nil
176+
return "Bearer " + tokenString, nil
177177
}
178178

179179
func runServ(c *cli.Context) error {
@@ -372,9 +372,9 @@ func runServ(c *cli.Context) error {
372372
repo_module.EnvPusherEmail+"="+results.UserEmail,
373373
repo_module.EnvPusherID+"="+strconv.FormatInt(results.UserID, 10),
374374
repo_module.EnvRepoID+"="+strconv.FormatInt(results.RepoID, 10),
375-
repo_module.EnvPRID+"="+fmt.Sprintf("%d", 0),
376-
repo_module.EnvDeployKeyID+"="+fmt.Sprintf("%d", results.DeployKeyID),
377-
repo_module.EnvKeyID+"="+fmt.Sprintf("%d", results.KeyID),
375+
repo_module.EnvPRID+"="+strconv.Itoa(0),
376+
repo_module.EnvDeployKeyID+"="+strconv.FormatInt(results.DeployKeyID, 10),
377+
repo_module.EnvKeyID+"="+strconv.FormatInt(results.KeyID, 10),
378378
repo_module.EnvAppURL+"="+setting.AppURL,
379379
)
380380
// to avoid breaking, here only use the minimal environment variables for the "gitea serv" command.

cmd/web_acme.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ func runACME(listenAddr string, m http.Handler) error {
136136
}
137137

138138
func runLetsEncryptFallbackHandler(w http.ResponseWriter, r *http.Request) {
139-
if r.Method != "GET" && r.Method != "HEAD" {
139+
if r.Method != http.MethodGet && r.Method != http.MethodHead {
140140
http.Error(w, "Use HTTPS", http.StatusBadRequest)
141141
return
142142
}

contrib/backport/backport.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package main
66

77
import (
88
"context"
9+
"errors"
910
"fmt"
1011
"log"
1112
"net/http"
@@ -158,7 +159,7 @@ func runBackport(c *cli.Context) error {
158159

159160
args := c.Args().Slice()
160161
if len(args) == 0 && pr == "" {
161-
return fmt.Errorf("no PR number provided\nProvide a PR number to backport")
162+
return errors.New("no PR number provided\nProvide a PR number to backport")
162163
} else if len(args) != 1 && pr == "" {
163164
return fmt.Errorf("multiple PRs provided %v\nOnly a single PR can be backported at a time", args)
164165
}

models/actions/run.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package actions
55

66
import (
77
"context"
8+
"errors"
89
"fmt"
910
"slices"
1011
"strings"
@@ -245,7 +246,7 @@ func CancelPreviousJobs(ctx context.Context, repoID int64, ref, workflowID strin
245246

246247
// If the update affected 0 rows, it means the job has changed in the meantime, so we need to try again.
247248
if n == 0 {
248-
return cancelledJobs, fmt.Errorf("job has changed, try again")
249+
return cancelledJobs, errors.New("job has changed, try again")
249250
}
250251

251252
cancelledJobs = append(cancelledJobs, job)
@@ -412,7 +413,7 @@ func UpdateRun(ctx context.Context, run *ActionRun, cols ...string) error {
412413
return err
413414
}
414415
if affected == 0 {
415-
return fmt.Errorf("run has changed")
416+
return errors.New("run has changed")
416417
// It's impossible that the run is not found, since Gitea never deletes runs.
417418
}
418419

models/actions/task.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package actions
66
import (
77
"context"
88
"crypto/subtle"
9+
"errors"
910
"fmt"
1011
"time"
1112

@@ -361,7 +362,7 @@ func UpdateTaskByState(ctx context.Context, runnerID int64, state *runnerv1.Task
361362
} else if !has {
362363
return nil, util.ErrNotExist
363364
} else if runnerID != task.RunnerID {
364-
return nil, fmt.Errorf("invalid runner for task")
365+
return nil, errors.New("invalid runner for task")
365366
}
366367

367368
if task.Status.IsDone() {

models/activities/action_list.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package activities
55

66
import (
77
"context"
8+
"errors"
89
"fmt"
910
"strconv"
1011

@@ -205,7 +206,7 @@ func (actions ActionList) LoadIssues(ctx context.Context) error {
205206
// GetFeeds returns actions according to the provided options
206207
func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, error) {
207208
if opts.RequestedUser == nil && opts.RequestedTeam == nil && opts.RequestedRepo == nil {
208-
return nil, 0, fmt.Errorf("need at least one of these filters: RequestedUser, RequestedTeam, RequestedRepo")
209+
return nil, 0, errors.New("need at least one of these filters: RequestedUser, RequestedTeam, RequestedRepo")
209210
}
210211

211212
var err error

models/asymkey/error.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ func IsErrGPGKeyParsing(err error) bool {
132132
}
133133

134134
func (err ErrGPGKeyParsing) Error() string {
135-
return fmt.Sprintf("failed to parse gpg key %s", err.ParseError.Error())
135+
return "failed to parse gpg key " + err.ParseError.Error()
136136
}
137137

138138
// ErrGPGKeyNotExist represents a "GPGKeyNotExist" kind of error.

models/asymkey/gpg_key.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package asymkey
55

66
import (
77
"context"
8+
"errors"
89
"fmt"
910
"strings"
1011
"time"
@@ -207,7 +208,7 @@ func parseGPGKey(ctx context.Context, ownerID int64, e *openpgp.Entity, verified
207208
// deleteGPGKey does the actual key deletion
208209
func deleteGPGKey(ctx context.Context, keyID string) (int64, error) {
209210
if keyID == "" {
210-
return 0, fmt.Errorf("empty KeyId forbidden") // Should never happen but just to be sure
211+
return 0, errors.New("empty KeyId forbidden") // Should never happen but just to be sure
211212
}
212213
// Delete imported key
213214
n, err := db.GetEngine(ctx).Where("key_id=?", keyID).Delete(new(GPGKeyImport))

models/asymkey/gpg_key_commit_verification.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package asymkey
55

66
import (
7+
"errors"
78
"fmt"
89
"hash"
910

@@ -68,7 +69,7 @@ const (
6869
func verifySign(s *packet.Signature, h hash.Hash, k *GPGKey) error {
6970
// Check if key can sign
7071
if !k.CanSign {
71-
return fmt.Errorf("key can not sign")
72+
return errors.New("key can not sign")
7273
}
7374
// Decode key
7475
pkey, err := base64DecPubKey(k.Content)

0 commit comments

Comments
 (0)