chore: enable forcetypeassert linter, fix issues (#38804)

Enable [`forcetypeassert`](https://github.com/gostaticanalysis/forcetypeassert)
linter to prevent unchecked type assertions. ~650 issues fixed, most
fixes were clean, some use `setting.PanicInDevOrTesting`.

The only behaviour changes are where code would previously send a 500 error
or panic, a 4xx error is now emitted.

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
silverwind
2026-08-09 10:25:06 +00:00
committed by GitHub
co-authored by wxiaoguang
parent fac8bf2eca
commit 76a81b24f9
248 changed files with 1110 additions and 995 deletions
+1
View File
@@ -11,6 +11,7 @@ linters:
- dupl
- errcheck
- forbidigo
- forcetypeassert
- gocheckcompilerdirectives
- gocritic
- govet
+27 -17
View File
@@ -354,13 +354,10 @@ func findLdapSecurityProtocolByName(name string) (ldap.SecurityProtocol, bool) {
return 0, false
}
// getAuthSource gets the login source by its id defined in the command line flags.
// It returns an error if the id is not set, does not match any source or if the source is not of expected type.
func (a *authService) getAuthSource(ctx context.Context, c *cli.Command, authType auth.Type) (*auth.Source, error) {
if err := argsSet(c, "id"); err != nil {
return nil, err
}
authSource, err := a.getAuthSourceByID(ctx, c.Int64("id"))
// getAuthSourceOfType gets the login source by id.
// It returns an error if the id does not match any source or if the source is not of the expected type.
func (a *authService) getAuthSourceOfType(ctx context.Context, id int64, authType auth.Type) (*auth.Source, error) {
authSource, err := a.getAuthSourceByID(ctx, id)
if err != nil {
return nil, err
}
@@ -372,6 +369,15 @@ func (a *authService) getAuthSource(ctx context.Context, c *cli.Command, authTyp
return authSource, nil
}
// getAuthSource gets the login source by its id defined in the command line flags.
// It returns an error if the id is not set, does not match any source or if the source is not of expected type.
func (a *authService) getAuthSource(ctx context.Context, c *cli.Command, authType auth.Type) (*auth.Source, error) {
if err := argsSet(c, "id"); err != nil {
return nil, err
}
return a.getAuthSourceOfType(ctx, c.Int64("id"), authType)
}
// addLdapBindDn adds a new LDAP via Bind DN authentication source.
func (a *authService) addLdapBindDn(ctx context.Context, c *cli.Command) error {
if err := argsSet(c, "name", "security-protocol", "host", "port", "user-search-base", "user-filter", "email-attribute"); err != nil {
@@ -381,16 +387,17 @@ func (a *authService) addLdapBindDn(ctx context.Context, c *cli.Command) error {
return err
}
ldapConfig := &ldap.Source{
Enabled: true, // always true
}
authSource := &auth.Source{
Type: auth.LDAP,
IsActive: true, // active by default
Cfg: &ldap.Source{
Enabled: true, // always true
},
Cfg: ldapConfig,
}
parseAuthSourceLdap(c, authSource)
if err := parseLdapConfig(c, authSource.Cfg.(*ldap.Source)); err != nil {
if err := parseLdapConfig(c, ldapConfig); err != nil {
return err
}
@@ -407,9 +414,10 @@ func (a *authService) updateLdapBindDn(ctx context.Context, c *cli.Command) erro
if err != nil {
return err
}
ldapConfig := auth.MustSourceCfg[*ldap.Source](authSource)
parseAuthSourceLdap(c, authSource)
if err := parseLdapConfig(c, authSource.Cfg.(*ldap.Source)); err != nil {
if err := parseLdapConfig(c, ldapConfig); err != nil {
return err
}
@@ -426,16 +434,17 @@ func (a *authService) addLdapSimpleAuth(ctx context.Context, c *cli.Command) err
return err
}
ldapConfig := &ldap.Source{
Enabled: true, // always true
}
authSource := &auth.Source{
Type: auth.DLDAP,
IsActive: true, // active by default
Cfg: &ldap.Source{
Enabled: true, // always true
},
Cfg: ldapConfig,
}
parseAuthSourceLdap(c, authSource)
if err := parseLdapConfig(c, authSource.Cfg.(*ldap.Source)); err != nil {
if err := parseLdapConfig(c, ldapConfig); err != nil {
return err
}
@@ -452,9 +461,10 @@ func (a *authService) updateLdapSimpleAuth(ctx context.Context, c *cli.Command)
if err != nil {
return err
}
ldapConfig := auth.MustSourceCfg[*ldap.Source](authSource)
parseAuthSourceLdap(c, authSource)
if err := parseLdapConfig(c, authSource.Cfg.(*ldap.Source)); err != nil {
if err := parseLdapConfig(c, ldapConfig); err != nil {
return err
}
+2 -3
View File
@@ -221,12 +221,11 @@ func (a *authService) runUpdateOauth(ctx context.Context, c *cli.Command) error
return err
}
source, err := a.getAuthSourceByID(ctx, c.Int64("id"))
source, err := a.getAuthSourceOfType(ctx, c.Int64("id"), auth_model.OAuth2)
if err != nil {
return err
}
oAuth2Config := source.Cfg.(*oauth2.Source)
oAuth2Config := auth_model.MustSourceCfg[*oauth2.Source](source)
if c.IsSet("name") {
source.Name = c.String("name")
+2 -3
View File
@@ -175,12 +175,11 @@ func (a *authService) runUpdateSMTP(ctx context.Context, c *cli.Command) error {
return err
}
source, err := a.getAuthSourceByID(ctx, c.Int64("id"))
source, err := a.getAuthSourceOfType(ctx, c.Int64("id"), auth_model.SMTP)
if err != nil {
return err
}
smtpConfig := source.Cfg.(*smtp.Source)
smtpConfig := auth_model.MustSourceCfg[*smtp.Source](source)
if err := parseSMTPConfig(c, smtpConfig); err != nil {
return err
+5 -4
View File
@@ -5,6 +5,7 @@ package v1_14
import (
"context"
"errors"
"fmt"
"strings"
@@ -106,8 +107,8 @@ func FixPublisherIDforTagReleases(ctx context.Context, x base.EngineMigration) e
commit, err := gitRepo.GetTagCommit(ctx, release.TagName)
if err != nil {
if git.IsErrNotExist(err) {
log.Warn("Unable to find commit %s for Tag: %s in [%d]%s/%s. Cannot update publisher ID.", err.(git.ErrNotExist).ID, release.TagName, repo.ID, repo.OwnerName, repo.Name)
if errNotExist, ok := errors.AsType[git.ErrNotExist](err); ok {
log.Warn("Unable to find commit %s for Tag: %s in [%d]%s/%s. Cannot update publisher ID.", errNotExist.ID, release.TagName, repo.ID, repo.OwnerName, repo.Name)
continue
}
log.Error("Error whilst getting commit for Tag: %s in [%d]%s/%s. Error: %v", release.TagName, repo.ID, repo.OwnerName, repo.Name, err)
@@ -118,8 +119,8 @@ func FixPublisherIDforTagReleases(ctx context.Context, x base.EngineMigration) e
log.Warn("Tag: %s in Repo[%d]%s/%s does not have a tagger.", release.TagName, repo.ID, repo.OwnerName, repo.Name)
commit, err = gitRepo.GetCommit(ctx, commit.ID.String())
if err != nil {
if git.IsErrNotExist(err) {
log.Warn("Unable to find commit %s for Tag: %s in [%d]%s/%s. Cannot update publisher ID.", err.(git.ErrNotExist).ID, release.TagName, repo.ID, repo.OwnerName, repo.Name)
if errNotExist, ok := errors.AsType[git.ErrNotExist](err); ok {
log.Warn("Unable to find commit %s for Tag: %s in [%d]%s/%s. Cannot update publisher ID.", errNotExist.ID, release.TagName, repo.ID, repo.OwnerName, repo.Name)
continue
}
log.Error("Error whilst getting commit for Tag: %s in [%d]%s/%s. Error: %v", release.TagName, repo.ID, repo.OwnerName, repo.Name, err)
+6 -6
View File
@@ -51,16 +51,16 @@ func AddPullRequestRebaseWithMerge(_ context.Context, x base.EngineMigration) er
// Allow the new merge style if all other merge styles are allowed
allowMergeRebase := true
if allowMerge, ok := unit.Config["AllowMerge"]; ok {
allowMergeRebase = allowMergeRebase && allowMerge.(bool)
if allowMerge, ok := unit.Config["AllowMerge"].(bool); ok {
allowMergeRebase = allowMergeRebase && allowMerge
}
if allowRebase, ok := unit.Config["AllowRebase"]; ok {
allowMergeRebase = allowMergeRebase && allowRebase.(bool)
if allowRebase, ok := unit.Config["AllowRebase"].(bool); ok {
allowMergeRebase = allowMergeRebase && allowRebase
}
if allowSquash, ok := unit.Config["AllowSquash"]; ok {
allowMergeRebase = allowMergeRebase && allowSquash.(bool)
if allowSquash, ok := unit.Config["AllowSquash"].(bool); ok {
allowMergeRebase = allowMergeRebase && allowSquash
}
if _, ok := unit.Config["AllowRebaseMerge"]; !ok {
+3 -2
View File
@@ -20,6 +20,7 @@ import (
"gitea.dev/modules/util"
"golang.org/x/crypto/ssh"
"xorm.io/builder"
)
// AuthorizedStringCommentPrefix is a magic tag
@@ -162,8 +163,8 @@ func appendAuthorizedKeysToFile(keys ...*PublicKey) error {
// RegeneratePublicKeys regenerates the authorized_keys file
func RegeneratePublicKeys(ctx context.Context, t io.Writer) error {
if err := db.GetEngine(ctx).Where("type != ?", KeyTypePrincipal).Iterate(new(PublicKey), func(idx int, bean any) (err error) {
return WriteAuthorizedStringForValidKey(bean.(*PublicKey), t)
if err := db.Iterate(ctx, builder.Neq{"type": KeyTypePrincipal}, func(ctx context.Context, key *PublicKey) error {
return WriteAuthorizedStringForValidKey(key, t)
}); err != nil {
return err
}
+16 -20
View File
@@ -98,20 +98,12 @@ type RegisterableSource interface {
var registeredConfigs = map[Type]func() Config{}
// RegisterTypeConfig register a config for a provided type
func RegisterTypeConfig(typ Type, exemplar Config) {
if reflect.TypeOf(exemplar).Kind() == reflect.Pointer {
// Pointer:
registeredConfigs[typ] = func() Config {
return reflect.New(reflect.ValueOf(exemplar).Elem().Type()).Interface().(Config)
}
return
}
// Not a Pointer
registeredConfigs[typ] = func() Config {
return reflect.New(reflect.TypeOf(exemplar)).Elem().Interface().(Config)
}
// RegisterTypeConfig register a config for a provided type, the exemplar argument only serves type inference
func RegisterTypeConfig[T interface {
*E
Config
}, E any](typ Type, _ T) {
registeredConfigs[typ] = func() Config { return T(new(E)) }
}
// Source represents an external way for authorizing users.
@@ -188,6 +180,16 @@ func (source *Source) IsSSPI() bool {
return source.Type == SSPI
}
// MustSourceCfg returns the source's config as T. The registry populates Cfg from the
// source type, so a mismatch is a programming error the caller can't recover from.
func MustSourceCfg[T Config](source *Source) T {
cfg, ok := source.Cfg.(T)
if !ok {
panic(fmt.Errorf("auth source %q (id=%d, type=%s) has config %T, expected %s", source.Name, source.ID, source.Type, source.Cfg, reflect.TypeFor[T]()))
}
return cfg
}
// HasTLS returns true of this source supports TLS.
func (source *Source) HasTLS() bool {
hasTLSer, ok := source.Cfg.(HasTLSer)
@@ -371,12 +373,6 @@ type ErrSourceAlreadyExist struct {
Name string
}
// IsErrSourceAlreadyExist checks if an error is a ErrSourceAlreadyExist.
func IsErrSourceAlreadyExist(err error) bool {
_, ok := err.(ErrSourceAlreadyExist)
return ok
}
func (err ErrSourceAlreadyExist) Error() string {
return fmt.Sprintf("login source already exists [name: %s]", err.Name)
}
+3 -1
View File
@@ -11,6 +11,7 @@ import (
"gitea.dev/models/unittest"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestInTransaction(t *testing.T) {
@@ -107,7 +108,8 @@ func TestContextSafety(t *testing.T) {
_ = db.GetEngine(ctx).Iterate(&TestModel1{}, func(i int, bean any) error {
// here: db.GetEngine(ctx) is always the unclosed "Iterate" *Session with autoResetStatement=false,
// and the internal states (including "cond" and others) are always there and not be reset in this callback.
m1 := bean.(*TestModel1)
m1, ok := bean.(*TestModel1)
require.True(t, ok)
assert.EqualValues(t, i+1, m1.ID)
// here: XORM bug, it fails because the SQL becomes "WHERE id=-1", "WHERE id=-1 AND id=-2", "WHERE id=-1 AND id=-2 AND id=-3" ...
-6
View File
@@ -14,12 +14,6 @@ type ErrCancelled struct {
Message string
}
// IsErrCancelled checks if an error is a ErrCancelled.
func IsErrCancelled(err error) bool {
_, ok := err.(ErrCancelled)
return ok
}
func (err ErrCancelled) Error() string {
return "Cancelled: " + err.Message
}
+9
View File
@@ -239,6 +239,15 @@ func GetPackageDescriptorWithCache(ctx context.Context, pv *PackageVersion, c *c
}, nil
}
// DescriptorMetadata returns the descriptor's metadata, which getPackageDescriptor has created from the package type
func DescriptorMetadata[T interface{ *E }, E any](pd *PackageDescriptor) T {
metadata, ok := pd.Metadata.(T)
if !ok {
panic(fmt.Errorf("package %s of type %s has metadata type %T instead of %T", pd.Package.Name, pd.Package.Type, pd.Metadata, metadata))
}
return metadata
}
// GetPackageFileDescriptor gets a package file descriptor for a package file
func GetPackageFileDescriptor(ctx context.Context, pf *PackageFile) (*PackageFileDescriptor, error) {
return getPackageFileDescriptor(ctx, pf, cache.NewEphemeralCache())
+21 -8
View File
@@ -5,6 +5,7 @@ package repo
import (
"context"
"fmt"
"gitea.dev/models/db"
"gitea.dev/models/perm"
@@ -295,44 +296,56 @@ func (r *RepoUnit) Unit() unit.Unit {
return unit.Units[r.Type]
}
// unitConfig returns the unit's config, which BeforeSet has created from the unit type
func unitConfig[T interface {
*E
convert.Conversion
}, E any](r *RepoUnit) T {
config, ok := r.Config.(T)
if !ok {
panic(fmt.Errorf("repo unit %d of type %s has config type %T instead of %T", r.ID, r.Type.LogString(), r.Config, config))
}
return config
}
// CodeConfig returns config for unit.TypeCode
func (r *RepoUnit) CodeConfig() *UnitConfig {
return r.Config.(*UnitConfig)
return unitConfig[*UnitConfig](r)
}
// PullRequestsConfig returns config for unit.TypePullRequests
func (r *RepoUnit) PullRequestsConfig() *PullRequestsConfig {
return r.Config.(*PullRequestsConfig)
return unitConfig[*PullRequestsConfig](r)
}
// ReleasesConfig returns config for unit.TypeReleases
func (r *RepoUnit) ReleasesConfig() *UnitConfig {
return r.Config.(*UnitConfig)
return unitConfig[*UnitConfig](r)
}
// ExternalWikiConfig returns config for unit.TypeExternalWiki
func (r *RepoUnit) ExternalWikiConfig() *ExternalWikiConfig {
return r.Config.(*ExternalWikiConfig)
return unitConfig[*ExternalWikiConfig](r)
}
// IssuesConfig returns config for unit.TypeIssues
func (r *RepoUnit) IssuesConfig() *IssuesConfig {
return r.Config.(*IssuesConfig)
return unitConfig[*IssuesConfig](r)
}
// ExternalTrackerConfig returns config for unit.TypeExternalTracker
func (r *RepoUnit) ExternalTrackerConfig() *ExternalTrackerConfig {
return r.Config.(*ExternalTrackerConfig)
return unitConfig[*ExternalTrackerConfig](r)
}
// ActionsConfig returns config for unit.ActionsConfig
func (r *RepoUnit) ActionsConfig() *ActionsConfig {
return r.Config.(*ActionsConfig)
return unitConfig[*ActionsConfig](r)
}
// ProjectsConfig returns config for unit.ProjectsConfig
func (r *RepoUnit) ProjectsConfig() *ProjectsConfig {
return r.Config.(*ProjectsConfig)
return unitConfig[*ProjectsConfig](r)
}
func getUnitsByRepoID(ctx context.Context, repoID int64) (units []*RepoUnit, err error) {
+16 -12
View File
@@ -34,7 +34,8 @@ type FixtureItem struct {
type fixturesLoaderInternal struct {
xormEngine *xorm.Engine
tableSyncMap sync.Map
tableSyncMu sync.Mutex
tableSynced map[string]bool
db *sql.DB
dbType schemas.DBType
fixtures map[string]*FixtureItem
@@ -152,32 +153,35 @@ func (f *fixturesLoaderInternal) Load() error {
ctx := context.WithValue(context.Background(), db.ContextKeyTestFixtures, true)
f.tableSyncMu.Lock()
defer f.tableSyncMu.Unlock()
for _, fixture := range f.fixtures {
synced, existing := f.tableSyncMap.Load(fixture.tableName)
if synced == true || !existing {
synced, existing := f.tableSynced[fixture.tableName]
if synced || !existing {
continue
}
if err := f.loadFixtures(tx, fixture); err != nil {
return fmt.Errorf("failed to load fixtures from %s: %w", fixture.fileFullPath, err)
}
f.tableSyncMap.Store(fixture.tableName, true)
f.tableSynced[fixture.tableName] = true
}
if err = tx.Commit(); err != nil {
return err
}
f.tableSyncMap.Range(func(k, v any) bool {
tableName, synced := k.(string), v.(bool)
for tableName, synced := range f.tableSynced {
if !synced && f.fixtures[tableName] == nil {
_, _ = f.xormEngine.Context(ctx).Exec("DELETE FROM `" + tableName + "`")
}
f.tableSyncMap.Store(tableName, true)
return true
})
f.tableSynced[tableName] = true
}
return nil
}
func (f *fixturesLoaderInternal) MarkTableChanged(tableName string) {
f.tableSyncMap.Store(tableName, false)
f.tableSyncMu.Lock()
defer f.tableSyncMu.Unlock()
f.tableSynced[tableName] = false
}
func FixturesFileFullPaths(dir string, files []string) (map[string]*FixtureItem, error) {
@@ -212,7 +216,7 @@ func NewFixturesLoader(x *xorm.Engine, opts FixturesOptions) (FixturesLoader, er
return nil, fmt.Errorf("failed to get fixtures files: %w", err)
}
f := &fixturesLoaderInternal{xormEngine: x, db: x.DB().DB, dbType: x.Dialect().URI().DBType, fixtures: fixtureItems}
f := &fixturesLoaderInternal{xormEngine: x, db: x.DB().DB, dbType: x.Dialect().URI().DBType, fixtures: fixtureItems, tableSynced: map[string]bool{}}
switch f.dbType {
case schemas.SQLITE:
f.quoteObject = func(s string) string { return fmt.Sprintf(`"%s"`, s) }
@@ -233,7 +237,7 @@ func NewFixturesLoader(x *xorm.Engine, opts FixturesOptions) (FixturesLoader, er
xormBeans, _ := db.NamesToBean()
for _, bean := range xormBeans {
beanTableName := x.TableName(bean)
f.tableSyncMap.Store(trimTableNameQuotes(beanTableName), false)
f.tableSynced[trimTableNameQuotes(beanTableName)] = false
}
return f, nil
}
+2 -2
View File
@@ -64,7 +64,7 @@ func MatchScopedWorkflows(
parsed []*ParsedScopedWorkflow,
consumerGitRepo *git.Repository,
consumerCommit *git.Commit,
triggedEvent webhook_module.HookEventType,
inputEvent webhook_module.HookEventType,
payload api.Payloader,
) (matched, filtered []*DetectedWorkflow) {
for _, p := range parsed {
@@ -78,7 +78,7 @@ func MatchScopedWorkflows(
TriggerEvent: evt,
Content: p.Content,
}
switch detectWorkflowMatch(ctx, consumerGitRepo, consumerCommit, triggedEvent, payload, evt) {
switch detectWorkflowMatch(ctx, consumerGitRepo, consumerCommit, inputEvent, payload, evt) {
case detectMatched:
matched = append(matched, dwf)
case detectFilteredOut:
+33 -14
View File
@@ -266,12 +266,22 @@ func DetectScheduledWorkflows(ctx context.Context, gitRepo *git.Repository, comm
return wfs, nil
}
func detectWorkflowMatch(ctx context.Context, gitRepo *git.Repository, commit *git.Commit, triggedEvent webhook_module.HookEventType, payload api.Payloader, evt *jobparser.Event) detectResult {
if !canGithubEventMatch(evt.Name, triggedEvent) {
// payloadAs returns the payload as the type the event is expected to carry
func payloadAs[T api.Payloader](payload api.Payloader, inputEvent webhook_module.HookEventType) T {
typedPayload, ok := payload.(T)
if !ok {
// the event type determines the payload type, so a mismatch can only be a programming error
panic(fmt.Errorf("event %q was triggered with payload type %T instead of %T", inputEvent, payload, typedPayload))
}
return typedPayload
}
func detectWorkflowMatch(ctx context.Context, gitRepo *git.Repository, commit *git.Commit, inputEvent webhook_module.HookEventType, payload api.Payloader, evt *jobparser.Event) detectResult {
if !canGithubEventMatch(evt.Name, inputEvent) {
return detectNotApplicable
}
switch triggedEvent {
switch inputEvent {
case // events with no activity types
webhook_module.HookEventCreate,
webhook_module.HookEventDelete,
@@ -279,21 +289,23 @@ func detectWorkflowMatch(ctx context.Context, gitRepo *git.Repository, commit *g
webhook_module.HookEventWiki,
webhook_module.HookEventSchedule:
if len(evt.Acts()) != 0 {
log.Warn("Ignore unsupported %s event arguments %v", triggedEvent, evt.Acts())
log.Warn("Ignore unsupported %s event arguments %v", inputEvent, evt.Acts())
}
// no special filter parameters for these events, just return true if name matched
return detectMatched
case // push
webhook_module.HookEventPush:
return matchPushEvent(ctx, gitRepo, commit, payload.(*api.PushPayload), evt)
pushPayload := payloadAs[*api.PushPayload](payload, inputEvent)
return matchPushEvent(ctx, gitRepo, commit, pushPayload, evt)
case // issues
webhook_module.HookEventIssues,
webhook_module.HookEventIssueAssign,
webhook_module.HookEventIssueLabel,
webhook_module.HookEventIssueMilestone:
if matchIssuesEvent(payload.(*api.IssuePayload), evt) {
issuePayload := payloadAs[*api.IssuePayload](payload, inputEvent)
if matchIssuesEvent(issuePayload, evt) {
return detectMatched
}
return detectNotApplicable
@@ -303,7 +315,8 @@ func detectWorkflowMatch(ctx context.Context, gitRepo *git.Repository, commit *g
// `pull_request_comment` is same as `issue_comment`
// See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_comment-use-issue_comment
webhook_module.HookEventPullRequestComment:
if matchIssueCommentEvent(payload.(*api.IssueCommentPayload), evt) {
issueCommentPayload := payloadAs[*api.IssueCommentPayload](payload, inputEvent)
if matchIssueCommentEvent(issueCommentPayload, evt) {
return detectMatched
}
return detectNotApplicable
@@ -315,46 +328,52 @@ func detectWorkflowMatch(ctx context.Context, gitRepo *git.Repository, commit *g
webhook_module.HookEventPullRequestLabel,
webhook_module.HookEventPullRequestReviewRequest,
webhook_module.HookEventPullRequestMilestone:
return matchPullRequestEvent(ctx, gitRepo, commit, payload.(*api.PullRequestPayload), evt)
pullRequestPayload := payloadAs[*api.PullRequestPayload](payload, inputEvent)
return matchPullRequestEvent(ctx, gitRepo, commit, pullRequestPayload, evt)
case // pull_request_review
webhook_module.HookEventPullRequestReviewApproved,
webhook_module.HookEventPullRequestReviewRejected:
if matchPullRequestReviewEvent(payload.(*api.PullRequestPayload), evt) {
reviewPayload := payloadAs[*api.PullRequestPayload](payload, inputEvent)
if matchPullRequestReviewEvent(reviewPayload, evt) {
return detectMatched
}
return detectNotApplicable
case // pull_request_review_comment
webhook_module.HookEventPullRequestReviewComment:
if matchPullRequestReviewCommentEvent(payload.(*api.PullRequestPayload), evt) {
reviewCommentPayload := payloadAs[*api.PullRequestPayload](payload, inputEvent)
if matchPullRequestReviewCommentEvent(reviewCommentPayload, evt) {
return detectMatched
}
return detectNotApplicable
case // release
webhook_module.HookEventRelease:
if matchReleaseEvent(payload.(*api.ReleasePayload), evt) {
releasePayload := payloadAs[*api.ReleasePayload](payload, inputEvent)
if matchReleaseEvent(releasePayload, evt) {
return detectMatched
}
return detectNotApplicable
case // registry_package
webhook_module.HookEventPackage:
if matchPackageEvent(payload.(*api.PackagePayload), evt) {
packagePayload := payloadAs[*api.PackagePayload](payload, inputEvent)
if matchPackageEvent(packagePayload, evt) {
return detectMatched
}
return detectNotApplicable
case // workflow_run
webhook_module.HookEventWorkflowRun:
if matchWorkflowRunEvent(payload.(*api.WorkflowRunPayload), evt) {
workflowRunPayload := payloadAs[*api.WorkflowRunPayload](payload, inputEvent)
if matchWorkflowRunEvent(workflowRunPayload, evt) {
return detectMatched
}
return detectNotApplicable
default:
log.Warn("unsupported event %q", triggedEvent)
log.Warn("unsupported event %q", inputEvent)
return detectNotApplicable
}
}
+7 -3
View File
@@ -37,7 +37,9 @@ func TestEmbed(t *testing.T) {
assert.Equal(t, "a", string(content))
fi, err := fs.Stat(efs, "a.txt")
require.NoError(t, err)
_, ok := fi.(EmbeddedFileInfo).GetGzipContent()
fiEmbedded, ok := fi.(EmbeddedFileInfo)
require.True(t, ok)
_, ok = fiEmbedded.GetGzipContent()
assert.False(t, ok)
// test a compressed file
@@ -48,7 +50,9 @@ func TestEmbed(t *testing.T) {
require.NoError(t, err)
assert.False(t, fi.Mode().IsDir())
assert.True(t, fi.Mode().IsRegular())
gzipContent, ok := fi.(EmbeddedFileInfo).GetGzipContent()
fiEmbedded, ok = fi.(EmbeddedFileInfo)
require.True(t, ok)
gzipContent, ok := fiEmbedded.GetGzipContent()
assert.True(t, ok)
assert.Greater(t, len(gzipContent), 1)
assert.Less(t, len(gzipContent), 1000)
@@ -82,7 +86,7 @@ func TestEmbed(t *testing.T) {
require.NoError(t, err)
hi, err := hf.Stat()
require.NoError(t, err)
fiEmbedded, ok := hi.(EmbeddedFileInfo)
fiEmbedded, ok = hi.(EmbeddedFileInfo)
require.True(t, ok)
gzipContent, ok = fiEmbedded.GetGzipContent()
assert.True(t, ok)
+7 -5
View File
@@ -64,15 +64,17 @@ func CreateTimeLimitCode[T time.Time | string](data string, minutes int, startTi
const format = "200601021504"
var start time.Time
var startTimeAny any = startTimeGeneric
if t, ok := startTimeAny.(time.Time); ok {
start = t
} else {
switch startTime := any(startTimeGeneric).(type) {
case time.Time:
start = startTime
case string:
var err error
start, err = time.ParseInLocation(format, startTimeAny.(string), time.Local)
start, err = time.ParseInLocation(format, startTime, time.Local)
if err != nil {
return "" // return an invalid code because the "parse" failed
}
default:
panic(fmt.Sprintf("unsupported start time type %T", startTime)) // it shouldn't happen
}
startStr := start.Format(format)
end := start.Add(time.Minute * time.Duration(minutes))
+1 -1
View File
@@ -25,7 +25,7 @@ func TestWithCacheContext(t *testing.T) {
c.Put(field, "my_config1", 1)
v, _ = c.Get(field, "my_config1")
assert.NotNil(t, v)
assert.Equal(t, 1, v.(int))
assert.Equal(t, 1, v)
c.Delete(field, "my_config1")
c.Delete(field, "my_config2") // remove a non-exist key
+2 -2
View File
@@ -82,7 +82,7 @@ func getLastCommitForPathsByCommitNode(ctx context.Context, gitRepo *Repository,
// We do a tree traversal with nodes sorted by commit time
heap := binaryheap.NewWith(func(a, b any) int {
if a.(*commitAndPaths).commit.CommitTime().Before(b.(*commitAndPaths).commit.CommitTime()) {
if a.(*commitAndPaths).commit.CommitTime().Before(b.(*commitAndPaths).commit.CommitTime()) { //nolint:forcetypeassert // this heap only ever holds *commitAndPaths
return 1
}
return -1
@@ -110,7 +110,7 @@ heaploop:
if !ok {
break
}
current := cIn.(*commitAndPaths)
current := cIn.(*commitAndPaths) //nolint:forcetypeassert // this heap only ever holds *commitAndPaths
// Load the parent commits for the one we are currently examining
numParents := current.commit.NumParents()
+1 -1
View File
@@ -144,7 +144,7 @@ func (repo *Repository) GetTagInfos(ctx context.Context, page, pageSize int) ([]
sortTagsByTime(tags)
tagsTotal = len(tags)
if page != 0 {
tags = util.PaginateSlice(tags, page, pageSize).([]*Tag)
tags = util.PaginateSlice(tags, page, pageSize)
}
return nil
}).
+3 -1
View File
@@ -174,8 +174,10 @@ func TestGlob(t *testing.T) {
} {
g, err := Compile(test.pattern, test.delimiters...)
require.NoError(t, err)
compiler, ok := g.(*globCompiler)
require.True(t, ok)
result := g.Match(test.match)
assert.Equal(t, test.should, result, "pattern %q matching %q should be %v but got %v, compiled=%s", test.pattern, test.match, test.should, result, g.(*globCompiler).regexpPattern)
assert.Equal(t, test.should, result, "pattern %q matching %q should be %v but got %v, compiled=%s", test.pattern, test.match, test.should, result, compiler.regexpPattern)
}
}
+3 -1
View File
@@ -21,7 +21,9 @@ func TestLockAndDo(t *testing.T) {
locker := newTestRedisLocker(t)
defaultLocker.Store(new(locker))
testLockAndDo(t)
require.NoError(t, locker.(*redisLocker).Close())
rl, ok := locker.(*redisLocker)
require.True(t, ok)
require.NoError(t, rl.Close())
})
t.Run("memory", func(t *testing.T) {
defaultLocker.Store(new(NewMemoryLocker()))
+9 -4
View File
@@ -26,13 +26,17 @@ func TestLocker(t *testing.T) {
defer test.MockVariableValue(&redisLockExpiry, 5*time.Second)() // make it shorter for testing
locker := newTestRedisLocker(t)
testLocker(t, locker)
testRedisLocker(t, locker.(*redisLocker))
require.NoError(t, locker.(*redisLocker).Close())
rl, ok := locker.(*redisLocker)
require.True(t, ok)
testRedisLocker(t, rl)
require.NoError(t, rl.Close())
})
t.Run("memory", func(t *testing.T) {
locker := NewMemoryLocker()
testLocker(t, locker)
testMemoryLocker(t, locker.(*memoryLocker))
ml, ok := locker.(*memoryLocker)
require.True(t, ok)
testMemoryLocker(t, ml)
})
}
@@ -162,7 +166,8 @@ func testRedisLocker(t *testing.T, locker *redisLocker) {
// It simulates that there are some problems with extending like network issues or redis server down.
v, ok := locker.mutexM.Load("test")
require.True(t, ok)
m := v.(*redsync.Mutex)
m, ok := v.(*redsync.Mutex)
require.True(t, ok)
_, _ = m.Unlock() // release it to make it impossible to extend
// In current design, callers can't know the lock can't be extended.
+5 -6
View File
@@ -52,11 +52,10 @@ func (l *redisLocker) Lock(ctx context.Context, key string) (ReleaseFunc, error)
func (l *redisLocker) TryLock(ctx context.Context, key string) (bool, ReleaseFunc, error) {
f, err := l.lock(ctx, key, 1)
var (
errTaken *redsync.ErrTaken
errNodeTaken *redsync.ErrNodeTaken
)
if errors.As(err, &errTaken) || errors.As(err, &errNodeTaken) {
if _, taken := errors.AsType[*redsync.ErrTaken](err); taken {
return false, f, nil
}
if _, nodeTaken := errors.AsType[*redsync.ErrNodeTaken](err); nodeTaken {
return false, f, nil
}
return err == nil, f, err
@@ -112,7 +111,7 @@ func (l *redisLocker) startExtend() {
toExtend := make([]*redsync.Mutex, 0)
l.mutexM.Range(func(_, value any) bool {
m := value.(*redsync.Mutex)
m := value.(*redsync.Mutex) //nolint:forcetypeassert // mutexM only ever holds *redsync.Mutex
// Extend the lock if it is not expired.
// Although the mutex will be removed from the map before it is released,
+5 -2
View File
@@ -177,13 +177,15 @@ func GetListenerTCP(network string, address *net.TCPAddr) (*net.TCPListener, err
// look for a provided listener
for i, l := range providedListeners {
if isSameAddr(l.Addr(), address) {
tcpListener := l.(*net.TCPListener) //nolint:forcetypeassert // a listener matching a *net.TCPAddr is a *net.TCPListener
providedListeners = append(providedListeners[:i], providedListeners[i+1:]...)
needsUnlink := providedListenersToUnlink[i]
providedListenersToUnlink = append(providedListenersToUnlink[:i], providedListenersToUnlink[i+1:]...)
activeListeners = append(activeListeners, l)
activeListenersToUnlink = append(activeListenersToUnlink, needsUnlink)
return l.(*net.TCPListener), nil
return tcpListener, nil
}
}
@@ -211,13 +213,14 @@ func GetListenerUnix(network string, address *net.UnixAddr) (*net.UnixListener,
// look for a provided listener
for i, l := range providedListeners {
if isSameAddr(l.Addr(), address) {
unixListener := l.(*net.UnixListener) //nolint:forcetypeassert // a listener matching a *net.UnixAddr is a *net.UnixListener
providedListeners = append(providedListeners[:i], providedListeners[i+1:]...)
needsUnlink := providedListenersToUnlink[i]
providedListenersToUnlink = append(providedListenersToUnlink[:i], providedListenersToUnlink[i+1:]...)
activeListenersToUnlink = append(activeListenersToUnlink, needsUnlink)
activeListeners = append(activeListeners, l)
unixListener := l.(*net.UnixListener)
if needsUnlink {
unixListener.SetUnlinkOnClose(true)
}
+6 -2
View File
@@ -44,10 +44,14 @@ func RestartProcess() (int, error) {
// Extract the fds from the listeners.
files := make([]*os.File, len(listeners))
for i, l := range listeners {
var err error
// Now, all our listeners actually have File() functions so instead of
// individually casting we just use a hacky interface
files[i], err = l.(filer).File()
lf, ok := l.(filer)
if !ok {
return 0, fmt.Errorf("listener %T does not provide a File", l)
}
var err error
files[i], err = lf.File()
if err != nil {
return 0, err
}
+6 -1
View File
@@ -7,6 +7,7 @@ package graceful
import (
"crypto/tls"
"fmt"
"net"
"os"
"strings"
@@ -260,7 +261,11 @@ func (wl *wrappedListener) Accept() (c net.Conn, err error) {
func (wl *wrappedListener) File() (*os.File, error) {
// returns a dup(2) - FD_CLOEXEC flag *not* set so the listening socket can be passed to child processes
return wl.Listener.(filer).File()
lf, ok := wl.Listener.(filer)
if !ok {
return nil, fmt.Errorf("listener %T does not provide a File", wl.Listener)
}
return lf.File()
}
type wrappedConn struct {
+1 -1
View File
@@ -63,7 +63,7 @@ func (t *traceBuiltinSpan) toString(out *strings.Builder, indent int) {
}
out.WriteString("\n")
for _, c := range t.ts.children {
span := c.internalSpans[t.internalSpanIdx].(*traceBuiltinSpan)
span := c.internalSpans[t.internalSpanIdx].(*traceBuiltinSpan) //nolint:forcetypeassert // this tracer only stores its own spans
span.toString(out, indent+2)
}
}
+4 -1
View File
@@ -8,6 +8,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// "vendor span" is a simple demo for a span from a vendor library
@@ -82,7 +83,9 @@ func TestTraceStarter(t *testing.T) {
collectSpanNames(fullName, c)
}
}
collectSpanNames("", span.internalSpans[0].(*testTraceSpan).vendorSpan)
rootSpan, ok := span.internalSpans[0].(*testTraceSpan)
require.True(t, ok)
collectSpanNames("", rootSpan.vendorSpan)
assert.Equal(t, []string{
"/root",
"/root/span1",
+17 -6
View File
@@ -21,6 +21,7 @@ import (
"gitea.dev/modules/indexer/code/internal"
indexer_internal "gitea.dev/modules/indexer/internal"
inner_bleve "gitea.dev/modules/indexer/internal/bleve"
"gitea.dev/modules/json"
"gitea.dev/modules/setting"
"gitea.dev/modules/timeutil"
"gitea.dev/modules/typesniffer"
@@ -330,6 +331,17 @@ func (b *Indexer) Search(ctx context.Context, opts *internal.SearchOptions) (int
searchResults := make([]*internal.SearchResult, len(result.Hits))
for i, hit := range result.Hits {
content, okContent := hit.Fields["Content"].(string)
language, okLanguage := hit.Fields["Language"].(string)
commitID, okCommitID := hit.Fields["CommitID"].(string)
updatedAt, okUpdatedAt := hit.Fields["UpdatedAt"].(string)
repoID, okRepoID := hit.Fields["RepoID"].(float64)
if !okContent || !okLanguage || !okCommitID || !okUpdatedAt || !okRepoID {
hitFieldsJson, _ := json.Marshal(hit.Fields)
setting.PanicInDevOrTesting("unexpected field types in search hit %q: %s", hit.ID, string(hitFieldsJson))
return 0, nil, nil, fmt.Errorf("unexpected field types in search hit %q", hit.ID)
}
startIndex, endIndex := -1, -1
for _, locations := range hit.Locations["Content"] {
location := locations[0]
@@ -343,21 +355,20 @@ func (b *Indexer) Search(ctx context.Context, opts *internal.SearchOptions) (int
}
}
if len(hit.Locations["Filename"]) > 0 {
startIndex, endIndex = internal.FilenameMatchIndexPos(hit.Fields["Content"].(string))
startIndex, endIndex = internal.FilenameMatchIndexPos(content)
}
language := hit.Fields["Language"].(string)
var updatedUnix timeutil.TimeStamp
if t, err := time.Parse(time.RFC3339, hit.Fields["UpdatedAt"].(string)); err == nil {
if t, err := time.Parse(time.RFC3339, updatedAt); err == nil {
updatedUnix = timeutil.TimeStamp(t.Unix())
}
searchResults[i] = &internal.SearchResult{
RepoID: int64(hit.Fields["RepoID"].(float64)),
RepoID: int64(repoID),
StartIndex: startIndex,
EndIndex: endIndex,
Filename: internal.FilenameOfIndexerID(hit.ID),
Content: hit.Fields["Content"].(string),
CommitID: hit.Fields["CommitID"].(string),
Content: content,
CommitID: commitID,
UpdatedUnix: updatedUnix,
Language: language,
Color: enry.GetColor(language),
@@ -261,12 +261,21 @@ func convertResult(searchResult *es.SearchResponse, kw string, pageSize int) (in
return 0, nil, nil, err
}
content, okContent := res["content"].(string)
language, okLanguage := res["language"].(string)
commitID, okCommitID := res["commit_id"].(string)
updatedAt, okUpdatedAt := res["updated_at"].(float64)
if !okContent || !okLanguage || !okCommitID || !okUpdatedAt {
setting.PanicInDevOrTesting("unexpected field types in search hit %q: %s", hit.ID, string(hit.Source))
return 0, nil, nil, fmt.Errorf("unexpected field types in search hit %q", hit.ID)
}
// FIXME: There is no way to get the position the keyword on the content currently on the same request.
// So we get it from content, this may made the query slower. See
// https://discuss.elastic.co/t/fetching-position-of-keyword-in-matched-document/94291
var startIndex, endIndex int
if c, ok := hit.Highlight["filename"]; ok && len(c) > 0 {
startIndex, endIndex = internal.FilenameMatchIndexPos(res["content"].(string))
startIndex, endIndex = internal.FilenameMatchIndexPos(content)
} else if c, ok := hit.Highlight["content"]; ok && len(c) > 0 {
// FIXME: Since the highlighting content will include <em> and </em> for the keywords,
// now we should find the positions. But how to avoid html content which contains the
@@ -279,14 +288,12 @@ func convertResult(searchResult *es.SearchResponse, kw string, pageSize int) (in
panic(fmt.Sprintf("2===%#v", hit.Highlight))
}
language := res["language"].(string)
hits = append(hits, &internal.SearchResult{
RepoID: repoID,
Filename: fileName,
CommitID: res["commit_id"].(string),
Content: res["content"].(string),
UpdatedUnix: timeutil.TimeStamp(res["updated_at"].(float64)),
CommitID: commitID,
Content: content,
UpdatedUnix: timeutil.TimeStamp(updatedAt),
Language: language,
StartIndex: startIndex,
EndIndex: endIndex,
+1 -1
View File
@@ -24,7 +24,7 @@ var _ EventWriter = (*eventWriterConn)(nil)
func NewEventWriterConn(writerName string, writerMode WriterMode) EventWriter {
w := &eventWriterConn{EventWriterBaseImpl: NewEventWriterBase(writerName, "conn", writerMode)}
opt := writerMode.WriterOption.(WriterConnOption)
opt := writerMode.WriterOption.(WriterConnOption) //nolint:forcetypeassert // a conn writer is only created with WriterConnOption
w.connWriter = connWriter{
ReconnectOnMsg: opt.ReconnectOnMsg,
Reconnect: opt.Reconnect,
+1 -1
View File
@@ -21,7 +21,7 @@ var _ EventWriter = (*eventWriterConsole)(nil)
func NewEventWriterConsole(name string, mode WriterMode) EventWriter {
w := &eventWriterConsole{EventWriterBaseImpl: NewEventWriterBase(name, "console", mode)}
opt := mode.WriterOption.(WriterConsoleOption)
opt := mode.WriterOption.(WriterConsoleOption) //nolint:forcetypeassert // a console writer is only created with WriterConsoleOption
if opt.Stderr {
w.OutputWriteCloser = util.NopCloser{Writer: os.Stderr}
} else {
+1 -1
View File
@@ -29,7 +29,7 @@ var _ EventWriter = (*eventWriterFile)(nil)
func NewEventWriterFile(name string, mode WriterMode) EventWriter {
w := &eventWriterFile{EventWriterBaseImpl: NewEventWriterBase(name, "file", mode)}
opt := mode.WriterOption.(WriterFileOption)
opt := mode.WriterOption.(WriterFileOption) //nolint:forcetypeassert // a file writer is only created with WriterFileOption
var err error
w.fileWriter, err = rotatingfilewriter.Open(opt.FileName, &rotatingfilewriter.Options{
Rotate: opt.LogRotate,
+4 -1
View File
@@ -7,6 +7,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestSharedWorker(t *testing.T) {
@@ -37,6 +38,8 @@ func TestSharedWorker(t *testing.T) {
m.Close()
logs := w.(*dummyWriter).FetchLogs()
dw, ok := w.(*dummyWriter)
require.True(t, ok)
logs := dw.FetchLogs()
assert.Equal(t, []string{"msg-1\n", "msg-2\n", "msg-3\n"}, logs)
}
+13 -22
View File
@@ -237,10 +237,8 @@ func (b *footnoteBlockParser) Continue(node ast.Node, reader text.Reader, pc par
}
func (b *footnoteBlockParser) Close(node ast.Node, reader text.Reader, pc parser.Context) {
var list *FootnoteList
if tlist := pc.Get(footnoteListKey); tlist != nil {
list = tlist.(*FootnoteList)
} else {
list, _ := pc.Get(footnoteListKey).(*FootnoteList)
if list == nil {
list = NewFootnoteList()
pc.Set(footnoteListKey, list)
node.Parent().InsertBefore(node.Parent(), node, list)
@@ -295,17 +293,14 @@ func (s *footnoteParser) Parse(parent ast.Node, block text.Reader, pc parser.Con
value := block.Value(text.NewSegment(segment.Start+open, segment.Start+closes))
block.Advance(closes + 1)
var list *FootnoteList
if tlist := pc.Get(footnoteListKey); tlist != nil {
list = tlist.(*FootnoteList)
}
list, _ := pc.Get(footnoteListKey).(*FootnoteList)
if list == nil {
return nil
}
index := 0
name := []byte{}
for def := list.FirstChild(); def != nil; def = def.NextSibling() {
d := def.(*Footnote)
d := def.(*Footnote) //nolint:forcetypeassert // a FootnoteList only holds *Footnote children
if bytes.Equal(d.Ref, value) {
if d.Index < 0 {
list.Count++
@@ -339,10 +334,8 @@ func NewFootnoteASTTransformer() parser.ASTTransformer {
}
func (a *footnoteASTTransformer) Transform(node *ast.Document, reader text.Reader, pc parser.Context) {
var list *FootnoteList
if tlist := pc.Get(footnoteListKey); tlist != nil {
list = tlist.(*FootnoteList)
} else {
list, _ := pc.Get(footnoteListKey).(*FootnoteList)
if list == nil {
return
}
pc.Set(footnoteListKey, nil)
@@ -352,18 +345,16 @@ func (a *footnoteASTTransformer) Transform(node *ast.Document, reader text.Reade
if fc := container.LastChild(); fc != nil && ast.IsParagraph(fc) {
container = fc
}
footnoteNode := footnote.(*Footnote)
index := footnoteNode.Index
name := footnoteNode.Name
if index < 0 {
footnoteNode := footnote.(*Footnote) //nolint:forcetypeassert // a FootnoteList only holds *Footnote children
if footnoteNode.Index < 0 {
list.RemoveChild(list, footnote)
} else {
container.AppendChild(container, NewFootnoteBackLink(index, name))
container.AppendChild(container, NewFootnoteBackLink(footnoteNode.Index, footnoteNode.Name))
}
footnote = next
}
list.SortChildren(func(n1, n2 ast.Node) int {
if n1.(*Footnote).Index < n2.(*Footnote).Index {
if n1.(*Footnote).Index < n2.(*Footnote).Index { //nolint:forcetypeassert // a FootnoteList only holds *Footnote children
return -1
}
return 1
@@ -403,7 +394,7 @@ func (r *FootnoteHTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegist
func (r *FootnoteHTMLRenderer) renderFootnoteLink(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
if entering {
n := node.(*FootnoteLink)
n := node.(*FootnoteLink) //nolint:forcetypeassert // registered for KindFootnoteLink only
is := strconv.Itoa(n.Index)
_, _ = w.WriteString(`<sup id="fnref:user-content-`)
_, _ = w.Write(n.Name)
@@ -418,7 +409,7 @@ func (r *FootnoteHTMLRenderer) renderFootnoteLink(w util.BufWriter, source []byt
func (r *FootnoteHTMLRenderer) renderFootnoteBackLink(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
if entering {
n := node.(*FootnoteBackLink)
n := node.(*FootnoteBackLink) //nolint:forcetypeassert // registered for KindFootnoteBackLink only
_, _ = w.WriteString(` <a href="#fnref:user-content-`)
_, _ = w.Write(n.Name)
_, _ = w.WriteString(`" class="footnote-backref" role="doc-backlink">`)
@@ -429,7 +420,7 @@ func (r *FootnoteHTMLRenderer) renderFootnoteBackLink(w util.BufWriter, source [
}
func (r *FootnoteHTMLRenderer) renderFootnote(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
n := node.(*Footnote)
n := node.(*Footnote) //nolint:forcetypeassert // registered for KindFootnote only
if entering {
_, _ = w.WriteString(`<li id="fn:user-content-`)
_, _ = w.Write(n.Name)
+4 -6
View File
@@ -43,8 +43,8 @@ func (g *ASTTransformer) applyElementDir(n ast.Node) {
// Transform transforms the given AST tree.
func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc parser.Context) {
firstChild := node.FirstChild()
ctx := pc.Get(renderContextKey).(*markup.RenderContext)
rc := pc.Get(renderConfigKey).(*RenderConfig)
ctx := pc.Get(renderContextKey).(*markup.RenderContext) //nolint:forcetypeassert // the renderer always seeds this key before parsing
rc := pc.Get(renderConfigKey).(*RenderConfig) //nolint:forcetypeassert // the renderer always seeds this key before parsing
tocMode := ""
if rc.yamlNode != nil {
@@ -150,9 +150,7 @@ func (r *HTMLRenderer) renderCodeBlock(w util.BufWriter, source []byte, n ast.No
}
func (r *HTMLRenderer) renderDocument(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
n := node.(*ast.Document)
if val, has := n.AttributeString("lang"); has {
if val, has := node.AttributeString("lang"); has {
var err error
if entering {
_, err = w.WriteString("<div")
@@ -212,7 +210,7 @@ func (r *HTMLRenderer) renderRawHTML(w util.BufWriter, source []byte, node ast.N
if !entering {
return ast.WalkContinue, nil
}
n := node.(*RawHTML)
n := node.(*RawHTML) //nolint:forcetypeassert // registered for KindRawHTML only
_, err := w.WriteString(string(r.renderInternal.ProtectSafeAttrs(n.rawHTML)))
if err != nil {
return ast.WalkStop, err
+1 -1
View File
@@ -86,7 +86,7 @@ func (b *blockParser) Open(parent ast.Node, reader text.Reader, pc parser.Contex
// Continue parses the current line and returns a result of parsing.
func (b *blockParser) Continue(node ast.Node, reader text.Reader, pc parser.Context) parser.State {
block := node.(*Block)
block := node.(*Block) //nolint:forcetypeassert // this parser only ever opens *Block nodes
if block.Closed {
return parser.Close
}
@@ -49,7 +49,7 @@ func (r *BlockRenderer) writeLines(w util.BufWriter, source []byte, n gast.Node)
}
func (r *BlockRenderer) renderBlock(w util.BufWriter, source []byte, node gast.Node, entering bool) (gast.WalkStatus, error) {
n := node.(*Block)
n := node.(*Block) //nolint:forcetypeassert // registered for KindBlock only
if entering {
codeHTML := giteaUtil.Iif[template.HTML](n.Inline, "", `<pre class="code-block is-loading">`) + `<code class="language-math">`
_, _ = w.WriteString(string(r.renderInternal.ProtectSafeAttrs(codeHTML)))
+2 -2
View File
@@ -19,8 +19,8 @@ func (n *Inline) Inline() {}
// IsBlank returns if this inline node is empty
func (n *Inline) IsBlank(source []byte) bool {
for c := n.FirstChild(); c != nil; c = c.NextSibling() {
text := c.(*ast.Text).Segment
if !util.IsBlank(text.Value(source)) {
text := c.(*ast.Text) //nolint:forcetypeassert // an inline math node only holds text children
if !util.IsBlank(text.Segment.Value(source)) {
return false
}
}
@@ -160,12 +160,12 @@ func trimBlock(node *Inline, block text.Reader) {
}
// trim first space and last space
first := node.FirstChild().(*ast.Text)
first := node.FirstChild().(*ast.Text) //nolint:forcetypeassert // an inline math node only holds text children
if !(!first.Segment.IsEmpty() && block.Source()[first.Segment.Start] == ' ') {
return
}
last := node.LastChild().(*ast.Text)
last := node.LastChild().(*ast.Text) //nolint:forcetypeassert // an inline math node only holds text children
if !(!last.Segment.IsEmpty() && block.Source()[last.Segment.Stop-1] == ' ') {
return
}
@@ -30,7 +30,7 @@ func (r *InlineRenderer) renderInline(w util.BufWriter, source []byte, n ast.Nod
if entering {
_, _ = w.WriteString(string(r.renderInternal.ProtectSafeAttrs(`<code class="language-math">`)))
for c := n.FirstChild(); c != nil; c = c.NextSibling() {
segment := c.(*ast.Text).Segment
segment := c.(*ast.Text).Segment //nolint:forcetypeassert // an inline math node only holds text children
value := util.EscapeHTML(segment.Value(source))
if bytes.HasSuffix(value, []byte("\n")) {
_, _ = w.Write(value[:len(value)-1])
@@ -18,7 +18,7 @@ import (
// renderAttention renders a quote marked with i.e. "> **Note**" or "> [!Warning]" with a corresponding svg
func (r *HTMLRenderer) renderAttention(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
if entering {
n := node.(*Attention)
n := node.(*Attention) //nolint:forcetypeassert // registered for KindAttention only
var octiconName string
switch n.AttentionType {
case "tip":
+2 -2
View File
@@ -15,7 +15,7 @@ import (
)
func (r *HTMLRenderer) renderTaskCheckBoxListItem(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
n := node.(*TaskCheckBoxListItem)
n := node.(*TaskCheckBoxListItem) //nolint:forcetypeassert // registered for KindTaskCheckBoxListItem only
if entering {
if n.Attributes() != nil {
_, _ = w.WriteString("<li")
@@ -60,7 +60,7 @@ func (g *ASTTransformer) transformList(_ *markup.RenderContext, v *ast.List, rc
v.RemoveChildren(v)
for _, child := range children {
listItem := child.(*ast.ListItem)
listItem := child.(*ast.ListItem) //nolint:forcetypeassert // a list only holds list items
if !child.HasChildren() || !child.FirstChild().HasChildren() {
v.AppendChild(v, child)
continue
+2 -2
View File
@@ -22,8 +22,8 @@ func TestMigrationJSON_IssueOK(t *testing.T) {
func TestMigrationJSON_IssueFail(t *testing.T) {
issues := make([]*Issue, 0, 10)
err := Load("file_format_testdata/issue_b.json", &issues, true)
if _, ok := err.(*jsonschema.ValidationError); ok {
errors := strings.Split(err.(*jsonschema.ValidationError).GoString(), "\n")
if validationErr, ok := err.(*jsonschema.ValidationError); ok {
errors := strings.Split(validationErr.GoString(), "\n")
assert.Contains(t, errors[1], "missing properties")
assert.Contains(t, errors[1], "poster_id")
} else {
+17 -8
View File
@@ -56,21 +56,30 @@ func NewMultiHasher() *MultiHasher {
}
}
// marshalHash saves the state of a hash, every stdlib hash implements the marshaler interfaces
func marshalHash(h hash.Hash) ([]byte, error) {
return h.(encoding.BinaryMarshaler).MarshalBinary() //nolint:forcetypeassert // every hash used here is a stdlib hash
}
func unmarshalHash(h hash.Hash, state []byte) error {
return h.(encoding.BinaryUnmarshaler).UnmarshalBinary(state) //nolint:forcetypeassert // every hash used here is a stdlib hash
}
// MarshalBinary implements encoding.BinaryMarshaler
func (h *MultiHasher) MarshalBinary() ([]byte, error) {
md5Bytes, err := h.md5.(encoding.BinaryMarshaler).MarshalBinary()
md5Bytes, err := marshalHash(h.md5)
if err != nil {
return nil, err
}
sha1Bytes, err := h.sha1.(encoding.BinaryMarshaler).MarshalBinary()
sha1Bytes, err := marshalHash(h.sha1)
if err != nil {
return nil, err
}
sha256Bytes, err := h.sha256.(encoding.BinaryMarshaler).MarshalBinary()
sha256Bytes, err := marshalHash(h.sha256)
if err != nil {
return nil, err
}
sha512Bytes, err := h.sha512.(encoding.BinaryMarshaler).MarshalBinary()
sha512Bytes, err := marshalHash(h.sha512)
if err != nil {
return nil, err
}
@@ -89,22 +98,22 @@ func (h *MultiHasher) UnmarshalBinary(b []byte) error {
return errors.New("invalid hash state size")
}
if err := h.md5.(encoding.BinaryUnmarshaler).UnmarshalBinary(b[:marshaledSizeMD5]); err != nil {
if err := unmarshalHash(h.md5, b[:marshaledSizeMD5]); err != nil {
return err
}
b = b[marshaledSizeMD5:]
if err := h.sha1.(encoding.BinaryUnmarshaler).UnmarshalBinary(b[:marshaledSizeSHA1]); err != nil {
if err := unmarshalHash(h.sha1, b[:marshaledSizeSHA1]); err != nil {
return err
}
b = b[marshaledSizeSHA1:]
if err := h.sha256.(encoding.BinaryUnmarshaler).UnmarshalBinary(b[:marshaledSizeSHA256]); err != nil {
if err := unmarshalHash(h.sha256, b[:marshaledSizeSHA256]); err != nil {
return err
}
b = b[marshaledSizeSHA256:]
return h.sha512.(encoding.BinaryUnmarshaler).UnmarshalBinary(b[:marshaledSizeSHA512])
return unmarshalHash(h.sha512, b[:marshaledSizeSHA512])
}
// Write implements io.Writer
+7 -7
View File
@@ -107,13 +107,13 @@ func (e *MarshalEncoder) marshal(v any) error {
return e.marshalArray(val)
}
switch typ.Name() {
case "RubyUserMarshal":
return e.marshalUserMarshal(val.Interface().(RubyUserMarshal))
case "RubyUserDef":
return e.marshalUserDef(val.Interface().(RubyUserDef))
case "RubyObject":
return e.marshalObject(val.Interface().(RubyObject))
switch obj := val.Interface().(type) {
case RubyUserMarshal:
return e.marshalUserMarshal(obj)
case RubyUserDef:
return e.marshalUserDef(obj)
case RubyObject:
return e.marshalObject(obj)
}
return ErrUnsupportedType
+12
View File
@@ -5,13 +5,25 @@ package reqctx
import (
"context"
"fmt"
"io"
"maps"
"reflect"
"sync"
"gitea.dev/modules/process"
)
// MustContextValue returns the value stored under key. A missing or mistyped value can only
// be a programming error, and callers can't do anything useful with a zero value, so it panics.
func MustContextValue[T any](ctx context.Context, key any) T {
value, ok := ctx.Value(key).(T)
if !ok {
panic(fmt.Sprintf("context value %v is %T, expected %s", key, ctx.Value(key), reflect.TypeFor[T]()))
}
return value
}
type ContextDataProvider interface {
GetData() ContextData
}
+4 -4
View File
@@ -28,8 +28,8 @@ func RegenerateSession(resp http.ResponseWriter, req *http.Request) (Store, erro
f(resp, req)
}
if setting.IsInTesting {
if store := req.Context().Value(MockStoreContextKey); store != nil {
return store.(Store), nil
if store, ok := req.Context().Value(MockStoreContextKey).(Store); ok {
return store, nil
}
}
return session.RegenerateSession(resp, req)
@@ -37,8 +37,8 @@ func RegenerateSession(resp http.ResponseWriter, req *http.Request) (Store, erro
func GetContextSession(req *http.Request) Store {
if setting.IsInTesting {
if store := req.Context().Value(MockStoreContextKey); store != nil {
return store.(Store)
if store, ok := req.Context().Value(MockStoreContextKey).(Store); ok {
return store
}
}
return session.GetSession(req)
+1 -1
View File
@@ -99,7 +99,7 @@ func renderHTML(icon string, others ...any) (_ template.HTML, usingCache bool) {
cacheKey := svgCacheKey{icon, size, class}
cachedHTML, cached := svgCache.Load(cacheKey)
if cached && !svgItem.mocking {
return cachedHTML.(template.HTML), true
return cachedHTML.(template.HTML), true //nolint:forcetypeassert // svgCache only ever holds template.HTML
}
// the code is somewhat hacky, but it just works, because the SVG contents are all normalized
+3 -3
View File
@@ -145,7 +145,7 @@ func applyOp2(op operator, n1, n2 Num) Num {
f2, _ := util.ToFloat64(n2.Value)
return applyOp2Generic(op, f1, f2)
}
return applyOp2Generic(op, n1.Value.(int64), n2.Value.(int64))
return applyOp2Generic(op, n1.Value.(int64), n2.Value.(int64)) //nolint:forcetypeassert // castFloat64 above already ruled out float
}
func toOp(v any) (operator, error) {
@@ -321,13 +321,13 @@ func fnSum(nums []Num) Num {
if castFloat64(nums) {
var sum float64
for _, num := range nums {
sum += num.Value.(float64)
sum += num.Value.(float64) //nolint:forcetypeassert // castFloat64 reported every value is float64
}
return Num{sum}
}
var sum int64
for _, num := range nums {
sum += num.Value.(int64)
sum += num.Value.(int64) //nolint:forcetypeassert // castFloat64 ruled out float, so every value is int64
}
return Num{sum}
}
+4 -1
View File
@@ -9,6 +9,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func tokens(s string) (a []any) {
@@ -21,7 +22,9 @@ func tokens(s string) (a []any) {
func TestEval(t *testing.T) {
n, err := Expr(0, "/", 0.0)
assert.NoError(t, err)
assert.True(t, math.IsNaN(n.Value.(float64)))
nan, ok := n.Value.(float64)
require.True(t, ok)
assert.True(t, math.IsNaN(nan))
_, err = Expr(nil)
assert.ErrorContains(t, err, "unsupported token type")
+17 -21
View File
@@ -166,9 +166,9 @@ func newScopedTemplateSet(all *template.Template, name string) (*scopedTemplateS
var collectErr error // only need to collect the one error
collectTemplates = func(nodes []parse.Node) {
for _, node := range nodes {
if node.Type() == parse.NodeTemplate {
nodeTemplate := node.(*parse.TemplateNode)
subName := nodeTemplate.Name
switch node := node.(type) {
case *parse.TemplateNode:
subName := node.Name
if ts.htmlTemplates[subName] == nil {
subTmpl := all.Lookup(subName)
if subTmpl == nil {
@@ -185,26 +185,22 @@ func newScopedTemplateSet(all *template.Template, name string) (*scopedTemplateS
collectTemplates(subTmpl.Tree.Root.Nodes)
}
}
} else if node.Type() == parse.NodeList {
nodeList := node.(*parse.ListNode)
collectTemplates(nodeList.Nodes)
} else if node.Type() == parse.NodeIf {
nodeIf := node.(*parse.IfNode)
collectTemplates(nodeIf.BranchNode.List.Nodes)
if nodeIf.BranchNode.ElseList != nil {
collectTemplates(nodeIf.BranchNode.ElseList.Nodes)
case *parse.ListNode:
collectTemplates(node.Nodes)
case *parse.IfNode:
collectTemplates(node.BranchNode.List.Nodes)
if node.BranchNode.ElseList != nil {
collectTemplates(node.BranchNode.ElseList.Nodes)
}
} else if node.Type() == parse.NodeRange {
nodeRange := node.(*parse.RangeNode)
collectTemplates(nodeRange.BranchNode.List.Nodes)
if nodeRange.BranchNode.ElseList != nil {
collectTemplates(nodeRange.BranchNode.ElseList.Nodes)
case *parse.RangeNode:
collectTemplates(node.BranchNode.List.Nodes)
if node.BranchNode.ElseList != nil {
collectTemplates(node.BranchNode.ElseList.Nodes)
}
} else if node.Type() == parse.NodeWith {
nodeWith := node.(*parse.WithNode)
collectTemplates(nodeWith.BranchNode.List.Nodes)
if nodeWith.BranchNode.ElseList != nil {
collectTemplates(nodeWith.BranchNode.ElseList.Nodes)
case *parse.WithNode:
collectTemplates(node.BranchNode.List.Nodes)
if node.BranchNode.ElseList != nil {
collectTemplates(node.BranchNode.ElseList.Nodes)
}
}
}
+7 -3
View File
@@ -42,6 +42,10 @@ func NewRenderUtils(ctx reqctx.RequestContext) *RenderUtils {
return &RenderUtils{ctx: ctx, avatarUtils: NewAvatarUtils(ctx)}
}
func (ut *RenderUtils) locale() translation.Locale {
return ut.ctx.Value(translation.ContextKey).(translation.Locale) //nolint:forcetypeassert // the render context always carries a locale
}
// RenderCommitMessage renders commit message title (only title)
func (ut *RenderUtils) RenderCommitMessage(msg string, repo *repo.Repository) template.HTML {
msgLine := strings.TrimSpace(msg)
@@ -98,7 +102,7 @@ func (ut *RenderUtils) RenderIssueSimpleTitle(text string) template.HTML {
}
func (ut *RenderUtils) RenderLabel(label *issues_model.Label) template.HTML {
locale := ut.ctx.Value(translation.ContextKey).(translation.Locale)
locale := ut.locale()
var extraCSSClasses string
textColor := util.ContrastColor(label.Color)
labelScope := label.ExclusiveScope()
@@ -279,7 +283,7 @@ func (ut *RenderUtils) RenderUnicodeEscapeToggleButton(escapeStatus *charset.Esc
if escapeStatus == nil || !escapeStatus.Escaped {
return ""
}
locale := ut.ctx.Value(translation.ContextKey).(translation.Locale)
locale := ut.locale()
var title template.HTML
if escapeStatus.HasAmbiguous {
title += locale.Tr("repo.ambiguous_runes_line")
@@ -376,7 +380,7 @@ func (ut *RenderUtils) AvatarStackPushCommit(pushCommit *repository.PushCommit)
// AvatarStackWithNames renders the avatar stack plus a label: `name` / `a and b` / `N people` (opens popup).
func (ut *RenderUtils) AvatarStackWithNames(data *user_model.AvatarStackData) template.HTML {
locale := ut.ctx.Value(translation.ContextKey).(translation.Locale)
locale := ut.locale()
participants := data.Participants
var b htmlutil.HTMLBuilder
+1 -2
View File
@@ -11,7 +11,6 @@ import (
"gitea.dev/modules/htmlutil"
"gitea.dev/modules/setting"
"gitea.dev/modules/svg"
"gitea.dev/modules/translation"
"gitea.dev/modules/util"
)
@@ -35,7 +34,7 @@ func (ut *RenderUtils) RenderTimelineEventBadge(c *issues_model.Comment) templat
func (ut *RenderUtils) RenderTimelineEventComment(c *issues_model.Comment, createdStr template.HTML) template.HTML {
if c.Type == issues_model.CommentTypeChangeTitle {
locale := ut.ctx.Value(translation.ContextKey).(translation.Locale)
locale := ut.locale()
isToggle, isWip := commentTimelineEventIsWipToggle(c)
if !isToggle {
return locale.Tr("repo.issues.change_title_at", ut.RenderEmoji(c.OldTitle), ut.RenderEmoji(c.NewTitle), createdStr)
+5 -1
View File
@@ -72,12 +72,16 @@ func (store *localeStore) AddLocaleByJSON(langName, langDesc string, source, mor
l.idxToMsgMap[idx] = v
case map[string]any:
for key, val := range v {
valStr, ok := val.(string)
if !ok {
return fmt.Errorf("unsupported value type %T for key %q", val, trKey+"."+key)
}
idx, ok := store.trKeyToIdxMap[trKey+"."+key]
if !ok {
idx = len(store.trKeyToIdxMap)
store.trKeyToIdxMap[trKey+"."+key] = idx
}
l.idxToMsgMap[idx] = val.(string)
l.idxToMsgMap[idx] = valStr
}
default:
return fmt.Errorf("unsupported value type %T for key %q", v, trKey)
+1 -1
View File
@@ -20,7 +20,7 @@ import (
// httpClient returns an HTTP client that honors Gitea's proxy configuration.
var httpClient = util.OnceValue[*http.Client]{
Func: func() *http.Client {
transport := http.DefaultTransport.(*http.Transport).Clone()
transport := http.DefaultTransport.(*http.Transport).Clone() //nolint:forcetypeassert // Golang stdlib
transport.Proxy = proxy.Proxy()
return &http.Client{Transport: transport}
},
+8 -3
View File
@@ -8,6 +8,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestErrorTranslatable(t *testing.T) {
@@ -16,8 +17,10 @@ func TestErrorTranslatable(t *testing.T) {
err = ErrorWrapTranslatable(io.EOF, "key", 1)
assert.ErrorIs(t, err, io.EOF)
assert.Equal(t, "EOF", err.Error())
assert.Equal(t, "key", err.(*errorTranslatableWrapper).trKey)
assert.Equal(t, []any{1}, err.(*errorTranslatableWrapper).trArgs)
wrapped, ok := err.(*errorTranslatableWrapper)
require.True(t, ok)
assert.Equal(t, "key", wrapped.trKey)
assert.Equal(t, []any{1}, wrapped.trArgs)
err = ErrorWrap(err, "new msg %d", 100)
assert.ErrorIs(t, err, io.EOF)
@@ -25,5 +28,7 @@ func TestErrorTranslatable(t *testing.T) {
errTr := ErrorAsTranslatable(err)
assert.Equal(t, "EOF", errTr.Error())
assert.Equal(t, "key", errTr.(*errorTranslatableWrapper).trKey)
wrapped, ok = errTr.(*errorTranslatableWrapper)
require.True(t, ok)
assert.Equal(t, "key", wrapped.trKey)
}
+4 -1
View File
@@ -13,6 +13,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestKeygen(t *testing.T) {
@@ -55,6 +56,8 @@ func TestSignUsingKeys(t *testing.T) {
assert.NoError(t, err)
// Verify
err = rsa.VerifyPKCS1v15(pubParsed.(*rsa.PublicKey), crypto.SHA256, d, sig)
pubKey, ok := pubParsed.(*rsa.PublicKey)
require.True(t, ok)
err = rsa.VerifyPKCS1v15(pubKey, crypto.SHA256, d, sig)
assert.NoError(t, err)
}
-13
View File
@@ -1,13 +0,0 @@
// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package util
func GetMapValueOrDefault[T any](m map[string]any, key string, defaultValue T) T {
if value, ok := m[key]; ok {
if v, ok := value.(T); ok {
return v
}
}
return defaultValue
}
-26
View File
@@ -1,26 +0,0 @@
// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package util
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestGetMapValueOrDefault(t *testing.T) {
testMap := map[string]any{
"key1": "value1",
"key2": 42,
"key3": nil,
}
assert.Equal(t, "value1", GetMapValueOrDefault(testMap, "key1", "default"))
assert.Equal(t, 42, GetMapValueOrDefault(testMap, "key2", 0))
assert.Equal(t, "default", GetMapValueOrDefault(testMap, "key4", "default"))
assert.Equal(t, 100, GetMapValueOrDefault(testMap, "key5", 100))
assert.Equal(t, "default", GetMapValueOrDefault(testMap, "key3", "default"))
}
+7 -14
View File
@@ -3,31 +3,24 @@
package util
import "reflect"
// PaginateSlice cut a slice as per pagination options
// if page = 0 it do not paginate
func PaginateSlice(list any, page, pageSize int) any {
func PaginateSlice[S ~[]E, E any](list S, page, pageSize int) S {
if page <= 0 || pageSize <= 0 {
return list
}
if reflect.TypeOf(list).Kind() != reflect.Slice {
return list
}
listValue := reflect.ValueOf(list)
page--
if page*pageSize >= listValue.Len() {
return listValue.Slice(listValue.Len(), listValue.Len()).Interface()
if page*pageSize >= len(list) {
return list[len(list):]
}
listValue = listValue.Slice(page*pageSize, listValue.Len())
list = list[page*pageSize:]
if listValue.Len() > pageSize {
return listValue.Slice(0, pageSize).Interface()
if len(list) > pageSize {
return list[:pageSize]
}
return listValue.Interface()
return list
}
+7 -14
View File
@@ -11,24 +11,19 @@ import (
func TestPaginateSlice(t *testing.T) {
stringSlice := []string{"a", "b", "c", "d", "e"}
result, ok := PaginateSlice(stringSlice, 1, 2).([]string)
assert.True(t, ok)
result := PaginateSlice(stringSlice, 1, 2)
assert.Equal(t, []string{"a", "b"}, result)
result, ok = PaginateSlice(stringSlice, 100, 2).([]string)
assert.True(t, ok)
result = PaginateSlice(stringSlice, 100, 2)
assert.Equal(t, []string{}, result)
result, ok = PaginateSlice(stringSlice, 3, 2).([]string)
assert.True(t, ok)
result = PaginateSlice(stringSlice, 3, 2)
assert.Equal(t, []string{"e"}, result)
result, ok = PaginateSlice(stringSlice, 1, 0).([]string)
assert.True(t, ok)
result = PaginateSlice(stringSlice, 1, 0)
assert.Equal(t, []string{"a", "b", "c", "d", "e"}, result)
result, ok = PaginateSlice(stringSlice, 1, -1).([]string)
assert.True(t, ok)
result = PaginateSlice(stringSlice, 1, -1)
assert.Equal(t, []string{"a", "b", "c", "d", "e"}, result)
type Test struct {
@@ -36,11 +31,9 @@ func TestPaginateSlice(t *testing.T) {
}
testVar := []*Test{{Val: 2}, {Val: 3}, {Val: 4}}
testVar, ok = PaginateSlice(testVar, 1, 50).([]*Test)
assert.True(t, ok)
testVar = PaginateSlice(testVar, 1, 50)
assert.Equal(t, []*Test{{Val: 2}, {Val: 3}, {Val: 4}}, testVar)
testVar, ok = PaginateSlice(testVar, 2, 2).([]*Test)
assert.True(t, ok)
testVar = PaginateSlice(testVar, 2, 2)
assert.Equal(t, []*Test{{Val: 4}}, testVar)
}
+5 -4
View File
@@ -107,7 +107,7 @@ func FastCryptoRandomBytes(length int) []byte {
// ChaCha8 is about 20x times faster than system's crypto/rand.
// It is suitable for UUIDs, session IDs, etc
pool := chaCha8RandPool()
chaCha8Rand := pool.Get().(*rand2.ChaCha8)
chaCha8Rand := pool.Get().(*rand2.ChaCha8) //nolint:forcetypeassert // the pool's New only ever makes *rand2.ChaCha8
defer pool.Put(chaCha8Rand)
buf := make([]byte, length)
_, _ = chaCha8Rand.Read(buf)
@@ -270,15 +270,16 @@ func OptionalArg[T any](optArg []T, defaultValue ...T) (ret T) {
}
type EnumConst[T comparable] interface {
comparable
EnumValues() []T
}
// EnumValue returns the value if it's in the enum const's values,
// otherwise returns the first item of enums as default value.
func EnumValue[T comparable](val EnumConst[T]) (ret T, valid bool) {
func EnumValue[T EnumConst[T]](val T) (ret T, valid bool) {
enums := val.EnumValues()
if slices.Contains(enums, val.(T)) {
return val.(T), true
if slices.Contains(enums, val) {
return val, true
}
return enums[0], false
}
+7 -2
View File
@@ -4,6 +4,7 @@
package web
import (
"fmt"
"net/http"
"net/url"
"reflect"
@@ -37,8 +38,12 @@ func SetForm(dataStore reqctx.ContextDataProvider, obj any) {
}
// GetForm returns the validate form information
func GetForm(dataStore reqctx.RequestDataStore) any {
return dataStore.GetData()["__form"]
func GetForm[T any](dataStore reqctx.RequestDataStore) T {
form, ok := dataStore.GetData()["__form"].(T)
if !ok {
panic(fmt.Errorf("bound form %T does not match the requested type %s", dataStore.GetData()["__form"], reflect.TypeFor[T]()))
}
return form
}
// Router defines a route based on chi's router
+2 -2
View File
@@ -54,10 +54,10 @@ func (manager *loggerRequestManager) startSlowQueryDetector(threshold time.Durat
// print logs for slow requests
manager.reqRecords.Range(func(key, value any) bool {
index, record := key.(uint64), value.(*requestRecord)
record := value.(*requestRecord) //nolint:forcetypeassert // reqRecords only ever holds *requestRecord
if now.Sub(record.startTime) >= threshold {
manager.logPrint(StillExecutingEvent, record)
manager.reqRecords.Delete(index)
manager.reqRecords.Delete(key)
}
return true
})
+2 -1
View File
@@ -75,6 +75,7 @@ import (
"gitea.dev/modules/json"
"gitea.dev/modules/log"
"gitea.dev/modules/optional"
"gitea.dev/modules/reqctx"
"gitea.dev/modules/setting"
"gitea.dev/modules/storage"
"gitea.dev/modules/util"
@@ -98,7 +99,7 @@ type ArtifactContext struct {
func init() {
web.RegisterResponseStatusProvider[*ArtifactContext](func(req *http.Request) web_types.ResponseStatusProvider {
return req.Context().Value(artifactContextKey).(*ArtifactContext)
return reqctx.MustContextValue[*ArtifactContext](req.Context(), artifactContextKey)
})
}
+1 -1
View File
@@ -323,7 +323,7 @@ func mergeChunksForArtifact(ctx *ArtifactContext, chunks []*chunkFileItem, st st
readers := make([]io.Reader, 0, len(allChunks))
closeReaders := func() {
for _, r := range readers {
_ = r.(io.Closer).Close() // it guarantees to be io.Closer by the following loop's Open function
_ = r.(io.Closer).Close() //nolint:forcetypeassert // it guarantees to be io.Closer by the following loop's Open function
}
readers = nil
}
+1 -1
View File
@@ -127,7 +127,7 @@ func SearchPackages(ctx *context.Context) {
crates = append(crates, &SearchResultCrate{
Name: pd.Package.Name,
LatestVersion: pd.Version.Version,
Description: pd.Metadata.(*cargo_module.Metadata).Description,
Description: packages_model.DescriptorMetadata[*cargo_module.Metadata](pd).Description,
})
}
+6 -1
View File
@@ -78,7 +78,12 @@ func (a *Auth) Verify(req *http.Request, w http.ResponseWriter, store auth.DataS
return nil, err
}
if err := verifySignedHeaders(req, version, pub.(*rsa.PublicKey)); err != nil {
rsaPub, ok := pub.(*rsa.PublicKey)
if !ok {
return nil, errors.New("public key is not a RSA key")
}
if err := verifySignedHeaders(req, version, rsaPub); err != nil {
return nil, err
}
+4 -4
View File
@@ -71,7 +71,7 @@ func PackagesUniverse(ctx *context.Context) {
LocationType: "opscode",
LocationPath: baseURL,
DownloadURL: fmt.Sprintf("%s/cookbooks/%s/versions/%s/download", baseURL, url.PathEscape(pd.Package.Name), pd.Version.Version),
Dependencies: pd.Metadata.(*chef_module.Metadata).Dependencies,
Dependencies: packages_model.DescriptorMetadata[*chef_module.Metadata](pd).Dependencies,
}
}
@@ -128,7 +128,7 @@ func EnumeratePackages(ctx *context.Context) {
items := make([]*Item, 0, len(pds))
for _, pd := range pds {
metadata := pd.Metadata.(*chef_module.Metadata)
metadata := packages_model.DescriptorMetadata[*chef_module.Metadata](pd)
items = append(items, &Item{
CookbookName: pd.Package.Name,
@@ -193,7 +193,7 @@ func PackageMetadata(ctx *context.Context) {
latest := pds[len(pds)-1]
metadata := latest.Metadata.(*chef_module.Metadata)
metadata := packages_model.DescriptorMetadata[*chef_module.Metadata](latest)
ctx.JSON(http.StatusOK, &Result{
Name: latest.Package.Name,
@@ -241,7 +241,7 @@ func PackageVersionMetadata(ctx *context.Context) {
baseURL := fmt.Sprintf("%sapi/packages/%s/chef/api/v1/cookbooks/%s", setting.AppURL, ctx.Package.Owner.Name, url.PathEscape(pd.Package.Name))
metadata := pd.Metadata.(*chef_module.Metadata)
metadata := packages_model.DescriptorMetadata[*chef_module.Metadata](pd)
ctx.JSON(http.StatusOK, &Result{
Version: pd.Version.Version,
+2 -2
View File
@@ -50,7 +50,7 @@ func createSearchResultResponse(total int64, pds []*packages_model.PackageDescri
for _, pd := range pds {
results = append(results, &SearchResult{
Name: pd.Package.Name,
Description: pd.Metadata.(*composer_module.Metadata).Description,
Description: packages_model.DescriptorMetadata[*composer_module.Metadata](pd).Description,
Downloads: pd.Version.DownloadCount,
})
}
@@ -111,7 +111,7 @@ func createPackageMetadataResponse(ctx *context.Context, registryURL string, pds
Version: pd.Version.Version,
Type: packageType,
Created: pd.Version.CreatedUnix.AsLocalTime(),
Metadata: pd.Metadata.(*composer_module.Metadata),
Metadata: packages_model.DescriptorMetadata[*composer_module.Metadata](pd),
Dist: Dist{
Type: "zip",
URL: fmt.Sprintf("%s/files/%s/%s/%s", registryURL, url.PathEscape(pd.Package.LowerName), url.PathEscape(pd.Version.LowerVersion), url.PathEscape(pd.Files[0].File.LowerName)),
+35 -27
View File
@@ -103,6 +103,14 @@ func ExtractPathParameters(ctx *context.Context) {
ctx.Data[packageReferenceKey] = pref
}
func getRecipeReference(ctx *context.Context) *conan_module.RecipeReference {
return ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference) //nolint:forcetypeassert // must be valid
}
func getPackageReference(ctx *context.Context) *conan_module.PackageReference {
return ctx.Data[packageReferenceKey].(*conan_module.PackageReference) //nolint:forcetypeassert // must be valid
}
// Ping reports the server capabilities
func Ping(ctx *context.Context) {
ctx.RespHeader().Add("X-Conan-Server-Capabilities", "revisions") // complex_search,checksum_deploy,matrix_params
@@ -164,20 +172,20 @@ func CheckCredentials(ctx *context.Context) {
// RecipeSnapshot displays the recipe files with their md5 hash
func RecipeSnapshot(ctx *context.Context) {
rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
rref := getRecipeReference(ctx)
serveSnapshot(ctx, rref.AsKey())
}
// RecipeSnapshot displays the package files with their md5 hash
func PackageSnapshot(ctx *context.Context) {
pref := ctx.Data[packageReferenceKey].(*conan_module.PackageReference)
pref := getPackageReference(ctx)
serveSnapshot(ctx, pref.AsKey())
}
func serveSnapshot(ctx *context.Context, fileKey string) {
rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
rref := getRecipeReference(ctx)
pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypeConan, rref.Name, rref.Version)
if err != nil {
@@ -217,7 +225,7 @@ func serveSnapshot(ctx *context.Context, fileKey string) {
// RecipeDownloadURLs displays the recipe files with their download url
func RecipeDownloadURLs(ctx *context.Context) {
rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
rref := getRecipeReference(ctx)
serveDownloadURLs(
ctx,
@@ -228,7 +236,7 @@ func RecipeDownloadURLs(ctx *context.Context) {
// PackageDownloadURLs displays the package files with their download url
func PackageDownloadURLs(ctx *context.Context) {
pref := ctx.Data[packageReferenceKey].(*conan_module.PackageReference)
pref := getPackageReference(ctx)
serveDownloadURLs(
ctx,
@@ -238,7 +246,7 @@ func PackageDownloadURLs(ctx *context.Context) {
}
func serveDownloadURLs(ctx *context.Context, fileKey, downloadURL string) {
rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
rref := getRecipeReference(ctx)
pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypeConan, rref.Name, rref.Version)
if err != nil {
@@ -274,7 +282,7 @@ func serveDownloadURLs(ctx *context.Context, fileKey, downloadURL string) {
// RecipeUploadURLs displays the upload urls for the provided recipe files
func RecipeUploadURLs(ctx *context.Context) {
rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
rref := getRecipeReference(ctx)
serveUploadURLs(
ctx,
@@ -285,7 +293,7 @@ func RecipeUploadURLs(ctx *context.Context) {
// PackageUploadURLs displays the upload urls for the provided package files
func PackageUploadURLs(ctx *context.Context) {
pref := ctx.Data[packageReferenceKey].(*conan_module.PackageReference)
pref := getPackageReference(ctx)
serveUploadURLs(
ctx,
@@ -315,21 +323,21 @@ func serveUploadURLs(ctx *context.Context, fileFilter container.Set[string], upl
// UploadRecipeFile handles the upload of a recipe file
func UploadRecipeFile(ctx *context.Context) {
rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
rref := getRecipeReference(ctx)
uploadFile(ctx, recipeFileList, rref.AsKey())
}
// UploadPackageFile handles the upload of a package file
func UploadPackageFile(ctx *context.Context) {
pref := ctx.Data[packageReferenceKey].(*conan_module.PackageReference)
pref := getPackageReference(ctx)
uploadFile(ctx, packageFileList, pref.AsKey())
}
func uploadFile(ctx *context.Context, fileFilter container.Set[string], fileKey string) {
rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
pref := ctx.Data[packageReferenceKey].(*conan_module.PackageReference)
rref := getRecipeReference(ctx)
pref := getPackageReference(ctx)
filename := ctx.PathParam("filename")
if !fileFilter.Contains(filename) {
@@ -454,20 +462,20 @@ func uploadFile(ctx *context.Context, fileFilter container.Set[string], fileKey
// DownloadRecipeFile serves the content of the requested recipe file
func DownloadRecipeFile(ctx *context.Context) {
rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
rref := getRecipeReference(ctx)
downloadFile(ctx, recipeFileList, rref.AsKey())
}
// DownloadPackageFile serves the content of the requested package file
func DownloadPackageFile(ctx *context.Context) {
pref := ctx.Data[packageReferenceKey].(*conan_module.PackageReference)
pref := getPackageReference(ctx)
downloadFile(ctx, packageFileList, pref.AsKey())
}
func downloadFile(ctx *context.Context, fileFilter container.Set[string], fileKey string) {
rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
rref := getRecipeReference(ctx)
filename := ctx.PathParam("filename")
if !fileFilter.Contains(filename) {
@@ -503,7 +511,7 @@ func downloadFile(ctx *context.Context, fileFilter container.Set[string], fileKe
// DeleteRecipeV1 deletes the requested recipe(s)
func DeleteRecipeV1(ctx *context.Context) {
rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
rref := getRecipeReference(ctx)
if err := deleteRecipeOrPackage(ctx, rref, true, nil, false); err != nil {
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, conan_model.ErrPackageReferenceNotExist) {
@@ -518,7 +526,7 @@ func DeleteRecipeV1(ctx *context.Context) {
// DeleteRecipeV2 deletes the requested recipe(s) respecting its revisions
func DeleteRecipeV2(ctx *context.Context) {
rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
rref := getRecipeReference(ctx)
if err := deleteRecipeOrPackage(ctx, rref, rref.Revision == "", nil, false); err != nil {
if errors.Is(err, packages_model.ErrPackageNotExist) || errors.Is(err, conan_model.ErrPackageReferenceNotExist) {
@@ -533,7 +541,7 @@ func DeleteRecipeV2(ctx *context.Context) {
// DeletePackageV1 deletes the requested package(s)
func DeletePackageV1(ctx *context.Context) {
rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
rref := getRecipeReference(ctx)
type PackageReferences struct {
References []string `json:"package_ids"`
@@ -582,8 +590,8 @@ func DeletePackageV1(ctx *context.Context) {
// DeletePackageV2 deletes the requested package(s) respecting its revisions
func DeletePackageV2(ctx *context.Context) {
rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
pref := ctx.Data[packageReferenceKey].(*conan_module.PackageReference)
rref := getRecipeReference(ctx)
pref := getPackageReference(ctx)
if pref != nil { // has package reference
if err := deleteRecipeOrPackage(ctx, rref, false, pref, pref.Revision == ""); err != nil {
@@ -693,7 +701,7 @@ func deleteRecipeOrPackage(apictx *context.Context, rref *conan_module.RecipeRef
// ListRecipeRevisions gets a list of all recipe revisions
func ListRecipeRevisions(ctx *context.Context) {
rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
rref := getRecipeReference(ctx)
revisions, err := conan_model.GetRecipeRevisions(ctx, ctx.Package.Owner.ID, rref)
if err != nil {
@@ -706,7 +714,7 @@ func ListRecipeRevisions(ctx *context.Context) {
// ListPackageRevisions gets a list of all package revisions
func ListPackageRevisions(ctx *context.Context) {
pref := ctx.Data[packageReferenceKey].(*conan_module.PackageReference)
pref := getPackageReference(ctx)
revisions, err := conan_model.GetPackageRevisions(ctx, ctx.Package.Owner.ID, pref)
if err != nil {
@@ -742,7 +750,7 @@ func listRevisions(ctx *context.Context, revisions []*conan_model.PropertyValue)
// LatestRecipeRevision gets the latest recipe revision
func LatestRecipeRevision(ctx *context.Context) {
rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
rref := getRecipeReference(ctx)
revision, err := conan_model.GetLastRecipeRevision(ctx, ctx.Package.Owner.ID, rref)
if err != nil {
@@ -759,7 +767,7 @@ func LatestRecipeRevision(ctx *context.Context) {
// LatestPackageRevision gets the latest package revision
func LatestPackageRevision(ctx *context.Context) {
pref := ctx.Data[packageReferenceKey].(*conan_module.PackageReference)
pref := getPackageReference(ctx)
revision, err := conan_model.GetLastPackageRevision(ctx, ctx.Package.Owner.ID, pref)
if err != nil {
@@ -776,20 +784,20 @@ func LatestPackageRevision(ctx *context.Context) {
// ListRecipeRevisionFiles gets a list of all recipe revision files
func ListRecipeRevisionFiles(ctx *context.Context) {
rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
rref := getRecipeReference(ctx)
listRevisionFiles(ctx, rref.AsKey())
}
// ListPackageRevisionFiles gets a list of all package revision files
func ListPackageRevisionFiles(ctx *context.Context) {
pref := ctx.Data[packageReferenceKey].(*conan_module.PackageReference)
pref := getPackageReference(ctx)
listRevisionFiles(ctx, pref.AsKey())
}
func listRevisionFiles(ctx *context.Context, fileKey string) {
rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
rref := getRecipeReference(ctx)
pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypeConan, rref.Name, rref.Version)
if err != nil {
+1 -1
View File
@@ -72,7 +72,7 @@ func SearchPackagesV2(ctx *context.Context) {
}
func searchPackages(ctx *context.Context, searchAllRevisions bool) {
rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
rref := getRecipeReference(ctx)
if !searchAllRevisions && rref.Revision == "" {
lastRevision, err := conan_model.GetLastRecipeRevision(ctx, ctx.Package.Owner.ID, rref)
+1 -1
View File
@@ -138,7 +138,7 @@ func EnumeratePackages(ctx *context.Context) {
return
}
versionMetadata := pd.Metadata.(*conda_module.VersionMetadata)
versionMetadata := packages_model.DescriptorMetadata[*conda_module.VersionMetadata](pd)
pi := &PackageInfo{
Name: pd.PackageProperties.GetByName(conda_module.PropertyName),
+1 -1
View File
@@ -93,7 +93,7 @@ func enumeratePackages(ctx *context.Context, format string, opts *cran_model.Sea
}
}
metadata := pd.Metadata.(*cran_module.Metadata)
metadata := packages_model.DescriptorMetadata[*cran_module.Metadata](pd)
fmt.Fprintln(w, "Package:", pd.Package.Name)
fmt.Fprintln(w, "Version:", pd.Version.Version)
+3 -3
View File
@@ -45,7 +45,7 @@ func createPackageMetadataResponse(registryURL string, pds []*packages_model.Pac
latest := pds[len(pds)-1]
metadata := latest.Metadata.(*npm_module.Metadata)
metadata := packages_model.DescriptorMetadata[*npm_module.Metadata](latest)
return &npm_module.PackageMetadata{
ID: latest.Package.Name,
@@ -67,7 +67,7 @@ func createPackageMetadataResponse(registryURL string, pds []*packages_model.Pac
func createPackageMetadataVersion(registryURL string, pd *packages_model.PackageDescriptor) *npm_module.PackageMetadataVersion {
hashBytes, _ := hex.DecodeString(pd.Files[0].Blob.HashSHA512)
metadata := pd.Metadata.(*npm_module.Metadata)
metadata := packages_model.DescriptorMetadata[*npm_module.Metadata](pd)
return &npm_module.PackageMetadataVersion{
ID: fmt.Sprintf("%s@%s", pd.Package.Name, pd.Version.Version),
@@ -107,7 +107,7 @@ func createPackageMetadataVersion(registryURL string, pd *packages_model.Package
func createPackageSearchResponse(pds []*packages_model.PackageDescriptor, total int64) *npm_module.PackageSearch {
objects := make([]*npm_module.PackageSearchObject, 0, len(pds))
for _, pd := range pds {
metadata := pd.Metadata.(*npm_module.Metadata)
metadata := packages_model.DescriptorMetadata[*npm_module.Metadata](pd)
scope := metadata.Scope
if scope == "" {
+1 -5
View File
@@ -332,12 +332,8 @@ func createFeedResponse(l *linkBuilder, totalEntries int64, pds []*packages_mode
}
}
func createEntryResponse(l *linkBuilder, pd *packages_model.PackageDescriptor) *FeedEntry {
return createEntry(l, pd, true)
}
func createEntry(l *linkBuilder, pd *packages_model.PackageDescriptor, withNamespace bool) *FeedEntry {
metadata := pd.Metadata.(*nuget_module.Metadata)
metadata := packages_model.DescriptorMetadata[*nuget_module.Metadata](pd)
id := l.GetPackageMetadataURL(pd.Package.Name, pd.Version.Version)
+7 -9
View File
@@ -111,7 +111,7 @@ func createRegistrationIndexResponse(l *linkBuilder, pds []*packages_model.Packa
}
func createRegistrationIndexPageItem(l *linkBuilder, pd *packages_model.PackageDescriptor) *RegistrationIndexPageItem {
metadata := pd.Metadata.(*nuget_module.Metadata)
metadata := packages_model.DescriptorMetadata[*nuget_module.Metadata](pd)
return &RegistrationIndexPageItem{
RegistrationLeafURL: l.GetRegistrationLeafURL(pd.Package.Name, pd.Version.Version),
@@ -120,7 +120,7 @@ func createRegistrationIndexPageItem(l *linkBuilder, pd *packages_model.PackageD
CatalogLeafURL: l.GetRegistrationLeafURL(pd.Package.Name, pd.Version.Version),
Authors: metadata.Authors,
Copyright: metadata.Copyright,
DependencyGroups: createDependencyGroups(pd),
DependencyGroups: createDependencyGroups(metadata),
Description: metadata.Description,
IconURL: metadata.IconURL,
ID: pd.Package.Name,
@@ -139,9 +139,7 @@ func createRegistrationIndexPageItem(l *linkBuilder, pd *packages_model.PackageD
}
}
func createDependencyGroups(pd *packages_model.PackageDescriptor) []*PackageDependencyGroup {
metadata := pd.Metadata.(*nuget_module.Metadata)
func createDependencyGroups(metadata *nuget_module.Metadata) []*PackageDependencyGroup {
dependencyGroups := make([]*PackageDependencyGroup, 0, len(metadata.Dependencies))
for k, v := range metadata.Dependencies {
dependencies := make([]*PackageDependency, 0, len(v))
@@ -172,7 +170,7 @@ type RegistrationLeafResponse struct {
func createRegistrationLeafResponse(l *linkBuilder, pd *packages_model.PackageDescriptor) *RegistrationLeafResponse {
registrationLeafURL := l.GetRegistrationLeafURL(pd.Package.Name, pd.Version.Version)
packageDownloadURL := l.GetPackageDownloadURL(pd.Package.Name, pd.Version.Version)
metadata := pd.Metadata.(*nuget_module.Metadata)
metadata := packages_model.DescriptorMetadata[*nuget_module.Metadata](pd)
return &RegistrationLeafResponse{
RegistrationLeafURL: registrationLeafURL,
RegistrationIndexURL: l.GetRegistrationIndexURL(pd.Package.Name),
@@ -182,7 +180,7 @@ func createRegistrationLeafResponse(l *linkBuilder, pd *packages_model.PackageDe
CatalogLeafURL: registrationLeafURL,
Authors: metadata.Authors,
Copyright: metadata.Copyright,
DependencyGroups: createDependencyGroups(pd),
DependencyGroups: createDependencyGroups(metadata),
Description: metadata.Description,
IconURL: metadata.IconURL,
ID: pd.Package.Name,
@@ -290,13 +288,13 @@ func createSearchResult(l *linkBuilder, pds []*packages_model.PackageDescriptor)
})
}
metadata := latest.Metadata.(*nuget_module.Metadata)
metadata := packages_model.DescriptorMetadata[*nuget_module.Metadata](latest)
return &SearchResult{
Authors: metadata.Authors,
Copyright: metadata.Copyright,
Description: metadata.Description,
DependencyGroups: createDependencyGroups(latest),
DependencyGroups: createDependencyGroups(metadata),
IconURL: metadata.IconURL,
ID: latest.Package.Name,
IsPrerelease: latest.Version.IsPrerelease(),
+2 -1
View File
@@ -267,9 +267,10 @@ func RegistrationLeafV2(ctx *context.Context) {
return
}
resp := createEntryResponse(
resp := createEntry(
&linkBuilder{Base: setting.AppURL + "api/packages/" + ctx.Package.Owner.Name + "/nuget"},
pd,
true,
)
xmlResponse(ctx, http.StatusOK, resp)
+1 -1
View File
@@ -67,7 +67,7 @@ func packageDescriptorToMetadata(baseURL string, pd *packages_model.PackageDescr
Version: pd.Version.Version,
ArchiveURL: fmt.Sprintf("%s/files/%s.tar.gz", baseURL, url.PathEscape(pd.Version.Version)),
Published: pd.Version.CreatedUnix.AsLocalTime(),
Pubspec: pd.Metadata.(*pub_module.Metadata).Pubspec,
Pubspec: packages_model.DescriptorMetadata[*pub_module.Metadata](pd).Pubspec,
}
}
+3 -3
View File
@@ -75,7 +75,7 @@ func enumeratePackages(ctx *context.Context, filename string, pvs []*packages_mo
Name: "Gem::Version",
Value: []string{p.Version.Version},
},
p.Metadata.(*rubygems_module.Metadata).Platform,
packages_model.DescriptorMetadata[*rubygems_module.Metadata](p).Platform,
})
}
@@ -126,7 +126,7 @@ func ServePackageSpecification(ctx *context.Context) {
zw := zlib.NewWriter(ctx.Resp)
defer zw.Close()
metadata := pd.Metadata.(*rubygems_module.Metadata)
metadata := packages_model.DescriptorMetadata[*rubygems_module.Metadata](pd)
// create a Ruby Gem::Specification object
spec := &rubygems_module.RubyUserDef{
@@ -405,7 +405,7 @@ func makePackageVersionDependency(ctx *context.Context, version *packages_model.
return "", err
}
metadata := pd.Metadata.(*rubygems_module.Metadata)
metadata := packages_model.DescriptorMetadata[*rubygems_module.Metadata](pd)
fullFilename := makeGemFullFileName(pd.Package.Name, version.Version, metadata.Platform)
file, err := packages_model.GetFileForVersionByName(ctx, version.ID, fullFilename, "")
if err != nil {
+2 -2
View File
@@ -197,7 +197,7 @@ func PackageVersionMetadata(ctx *context.Context) {
return
}
metadata := pd.Metadata.(*swift_module.Metadata)
metadata := packages_model.DescriptorMetadata[*swift_module.Metadata](pd)
repositoryURLs := make([]string, 0, len(pd.VersionProperties))
for _, property := range pd.VersionProperties {
if property.Name == swift_module.PropertyRepositoryURL {
@@ -278,7 +278,7 @@ func DownloadManifest(ctx *context.Context) {
swiftVersion = swift_module.TrimmedVersionString(v)
}
}
m, ok := pd.Metadata.(*swift_module.Metadata).Manifests[swiftVersion]
m, ok := packages_model.DescriptorMetadata[*swift_module.Metadata](pd).Manifests[swiftVersion]
if !ok {
setResponseHeaders(ctx.Resp, &headers{
Status: http.StatusSeeOther,
+1 -1
View File
@@ -130,7 +130,7 @@ func EnumeratePackageVersions(ctx *context.Context) {
ctx.JSON(http.StatusOK, &packageMetadata{
Name: pds[0].Package.Name,
Description: pds[len(pds)-1].Metadata.(*vagrant_module.Metadata).Description,
Description: packages_model.DescriptorMetadata[*vagrant_module.Metadata](pds[len(pds)-1]).Description,
Versions: versions,
})
}
+1 -1
View File
@@ -39,7 +39,7 @@ func ListCronTasks(ctx *context.APIContext) {
count := len(tasks)
listOpts := utils.GetListOptions(ctx)
tasks = util.PaginateSlice(tasks, listOpts.Page, listOpts.PageSize).(cron.TaskTable)
tasks = util.PaginateSlice(tasks, listOpts.Page, listOpts.PageSize)
res := make([]structs.Cron, len(tasks))
for i, task := range tasks {
+2 -2
View File
@@ -137,7 +137,7 @@ func CreateHook(ctx *context.APIContext) {
// "201":
// "$ref": "#/responses/Hook"
form := web.GetForm(ctx).(*api.CreateHookOption)
form := web.GetForm[*api.CreateHookOption](ctx)
utils.AddSystemHook(ctx, form)
}
@@ -166,7 +166,7 @@ func EditHook(ctx *context.APIContext) {
// "200":
// "$ref": "#/responses/Hook"
form := web.GetForm(ctx).(*api.EditHookOption)
form := web.GetForm[*api.EditHookOption](ctx)
// TODO in body params
hookID := ctx.PathParamInt64("id")
+1 -1
View File
@@ -44,7 +44,7 @@ func CreateOrg(ctx *context.APIContext) {
// "422":
// "$ref": "#/responses/validationError"
form := web.GetForm(ctx).(*api.CreateOrgOption)
form := web.GetForm[*api.CreateOrgOption](ctx)
visibility := api.VisibleTypePublic
if form.Visibility != "" {
+1 -1
View File
@@ -43,7 +43,7 @@ func CreateRepo(ctx *context.APIContext) {
// "422":
// "$ref": "#/responses/validationError"
form := web.GetForm(ctx).(*api.CreateRepoOption)
form := web.GetForm[*api.CreateRepoOption](ctx)
repo.CreateUserRepo(ctx, ctx.ContextUser, *form)
}
+4 -4
View File
@@ -75,7 +75,7 @@ func CreateUser(ctx *context.APIContext) {
// "422":
// "$ref": "#/responses/validationError"
form := web.GetForm(ctx).(*api.CreateUserOption)
form := web.GetForm[*api.CreateUserOption](ctx)
u := &user_model.User{
Name: form.Username,
@@ -190,7 +190,7 @@ func EditUser(ctx *context.APIContext) {
// "422":
// "$ref": "#/responses/validationError"
form := web.GetForm(ctx).(*api.EditUserOption)
form := web.GetForm[*api.EditUserOption](ctx)
authOpts := &user_service.UpdateAuthOptions{
LoginSource: optional.FromNonDefault(form.SourceID),
@@ -340,7 +340,7 @@ func CreatePublicKey(ctx *context.APIContext) {
// "422":
// "$ref": "#/responses/validationError"
form := web.GetForm(ctx).(*api.CreateKeyOption)
form := web.GetForm[*api.CreateKeyOption](ctx)
user.CreateUserPublicKey(ctx, *form, ctx.ContextUser.ID)
}
@@ -551,7 +551,7 @@ func RenameUser(ctx *context.APIContext) {
return
}
newName := web.GetForm(ctx).(*api.RenameUserOption).NewName
newName := web.GetForm[*api.RenameUserOption](ctx).NewName
// Check if username has been changed
if err := user_service.RenameUser(ctx, ctx.ContextUser, newName, ctx.Doer); err != nil {
+2 -2
View File
@@ -66,7 +66,7 @@ func AddUserBadges(ctx *context.APIContext) {
// "403":
// "$ref": "#/responses/forbidden"
form := web.GetForm(ctx).(*api.UserBadgeOption)
form := web.GetForm[*api.UserBadgeOption](ctx)
badges := prepareBadgesForReplaceOrAdd(*form)
if err := user_model.AddUserBadges(ctx, ctx.ContextUser, badges); err != nil {
@@ -102,7 +102,7 @@ func DeleteUserBadges(ctx *context.APIContext) {
// "422":
// "$ref": "#/responses/validationError"
form := web.GetForm(ctx).(*api.UserBadgeOption)
form := web.GetForm[*api.UserBadgeOption](ctx)
badges := prepareBadgesForReplaceOrAdd(*form)
if err := user_model.RemoveUserBadges(ctx, ctx.ContextUser, badges); err != nil {
+1 -1
View File
@@ -396,7 +396,7 @@ func reqUsersExploreEnabled() func(ctx *context.APIContext) {
func reqBasicOrRevProxyAuth() func(ctx *context.APIContext) {
return func(ctx *context.APIContext) {
if ctx.IsSigned && setting.Service.EnableReverseProxyAuthAPI && ctx.Data["AuthedMethod"].(string) == auth.ReverseProxyMethodName {
if ctx.IsSigned && setting.Service.EnableReverseProxyAuthAPI && ctx.Data["AuthedMethod"] == auth.ReverseProxyMethodName {
return
}
if !ctx.IsBasicAuth {
+2 -2
View File
@@ -33,7 +33,7 @@ func Markup(ctx *context.APIContext) {
// "422":
// "$ref": "#/responses/validationError"
form := web.GetForm(ctx).(*api.MarkupOption)
form := web.GetForm[*api.MarkupOption](ctx)
mode := util.Iif(form.Wiki, "wiki", form.Mode) //nolint:staticcheck // form.Wiki is deprecated
common.RenderMarkup(ctx.Base, ctx.Repo, mode, form.Text, form.Context, form.FilePath)
}
@@ -58,7 +58,7 @@ func Markdown(ctx *context.APIContext) {
// "422":
// "$ref": "#/responses/validationError"
form := web.GetForm(ctx).(*api.MarkdownOption)
form := web.GetForm[*api.MarkdownOption](ctx)
mode := util.Iif(form.Wiki, "wiki", form.Mode) //nolint:staticcheck // form.Wiki is deprecated
common.RenderMarkup(ctx.Base, ctx.Repo, mode, form.Text, form.Context, "")
}
+3 -3
View File
@@ -106,7 +106,7 @@ func (Action) CreateOrUpdateSecret(ctx *context.APIContext) {
// "404":
// "$ref": "#/responses/notFound"
opt := web.GetForm(ctx).(*api.CreateOrUpdateSecretOption)
opt := web.GetForm[*api.CreateOrUpdateSecretOption](ctx)
_, created, err := secret_service.CreateOrUpdateSecret(ctx, ctx.Org.Organization.ID, 0, ctx.PathParam("secretname"), opt.Data, opt.Description)
if err != nil {
@@ -373,7 +373,7 @@ func (Action) CreateVariable(ctx *context.APIContext) {
// "500":
// "$ref": "#/responses/error"
opt := web.GetForm(ctx).(*api.CreateVariableOption)
opt := web.GetForm[*api.CreateVariableOption](ctx)
ownerID := ctx.Org.Organization.ID
variableName := ctx.PathParam("variablename")
@@ -437,7 +437,7 @@ func (Action) UpdateVariable(ctx *context.APIContext) {
// "404":
// "$ref": "#/responses/notFound"
opt := web.GetForm(ctx).(*api.UpdateVariableOption)
opt := web.GetForm[*api.UpdateVariableOption](ctx)
v, err := actions_service.GetVariable(ctx, actions_model.FindVariablesOpts{
OwnerID: ctx.Org.Organization.ID,
+1 -1
View File
@@ -35,7 +35,7 @@ func UpdateAvatar(ctx *context.APIContext) {
// "$ref": "#/responses/empty"
// "404":
// "$ref": "#/responses/notFound"
form := web.GetForm(ctx).(*api.UpdateUserAvatarOption)
form := web.GetForm[*api.UpdateUserAvatarOption](ctx)
content, err := base64.StdEncoding.DecodeString(form.Image)
if err != nil {
+2 -2
View File
@@ -113,7 +113,7 @@ func CreateHook(ctx *context.APIContext) {
utils.AddOwnerHook(
ctx,
ctx.ContextUser,
web.GetForm(ctx).(*api.CreateHookOption),
web.GetForm[*api.CreateHookOption](ctx),
)
}
@@ -151,7 +151,7 @@ func EditHook(ctx *context.APIContext) {
utils.EditOwnerHook(
ctx,
ctx.ContextUser,
web.GetForm(ctx).(*api.EditHookOption),
web.GetForm[*api.EditHookOption](ctx),
ctx.PathParamInt64("id"),
)
}
+2 -2
View File
@@ -86,7 +86,7 @@ func CreateLabel(ctx *context.APIContext) {
// "$ref": "#/responses/notFound"
// "422":
// "$ref": "#/responses/validationError"
form := web.GetForm(ctx).(*api.CreateLabelOption)
form := web.GetForm[*api.CreateLabelOption](ctx)
form.Color = strings.Trim(form.Color, " ")
color, err := label.NormalizeColor(form.Color)
if err != nil {
@@ -189,7 +189,7 @@ func EditLabel(ctx *context.APIContext) {
// "$ref": "#/responses/notFound"
// "422":
// "$ref": "#/responses/validationError"
form := web.GetForm(ctx).(*api.EditLabelOption)
form := web.GetForm[*api.EditLabelOption](ctx)
l, err := issues_model.GetLabelInOrgByID(ctx, ctx.Org.Organization.ID, ctx.PathParamInt64("id"))
if err != nil {
if issues_model.IsErrOrgLabelNotExist(err) {
+3 -3
View File
@@ -261,7 +261,7 @@ func Create(ctx *context.APIContext) {
// "$ref": "#/responses/forbidden"
// "422":
// "$ref": "#/responses/validationError"
form := web.GetForm(ctx).(*api.CreateOrgOption)
form := web.GetForm[*api.CreateOrgOption](ctx)
if !ctx.Doer.CanCreateOrganization() {
ctx.APIError(http.StatusForbidden, "not allowed to create org")
return
@@ -358,7 +358,7 @@ func Rename(ctx *context.APIContext) {
// "422":
// "$ref": "#/responses/validationError"
form := web.GetForm(ctx).(*api.RenameOrgOption)
form := web.GetForm[*api.RenameOrgOption](ctx)
orgUser := ctx.Org.Organization.AsUser()
if err := user_service.RenameUser(ctx, orgUser, form.NewName, ctx.Doer); err != nil {
if user_model.IsErrUserAlreadyExist(err) || db.IsErrNameReserved(err) || db.IsErrNamePatternNotAllowed(err) || db.IsErrNameCharsNotAllowed(err) {
@@ -397,7 +397,7 @@ func Edit(ctx *context.APIContext) {
// "404":
// "$ref": "#/responses/notFound"
form := web.GetForm(ctx).(*api.EditOrgOption)
form := web.GetForm[*api.EditOrgOption](ctx)
if err := org.UpdateOrgEmailAddress(ctx, ctx.Org.Organization, form.Email); err != nil {
if errors.Is(err, util.ErrInvalidArgument) {
+2 -2
View File
@@ -214,7 +214,7 @@ func CreateTeam(ctx *context.APIContext) {
// "$ref": "#/responses/notFound"
// "422":
// "$ref": "#/responses/validationError"
form := web.GetForm(ctx).(*api.CreateTeamOption)
form := web.GetForm[*api.CreateTeamOption](ctx)
teamPermission := perm.ParseAccessMode(string(form.Permission), perm.AccessModeNone, perm.AccessModeAdmin)
team := &organization.Team{
OrgID: ctx.Org.Organization.ID,
@@ -282,7 +282,7 @@ func EditTeam(ctx *context.APIContext) {
// "404":
// "$ref": "#/responses/notFound"
form := web.GetForm(ctx).(*api.EditTeamOption)
form := web.GetForm[*api.EditTeamOption](ctx)
team := ctx.Org.Team
if err := team.LoadUnits(ctx); err != nil {
ctx.APIErrorInternal(err)
+4 -4
View File
@@ -135,7 +135,7 @@ func (Action) CreateOrUpdateSecret(ctx *context.APIContext) {
repo := ctx.Repo.Repository
opt := web.GetForm(ctx).(*api.CreateOrUpdateSecretOption)
opt := web.GetForm[*api.CreateOrUpdateSecretOption](ctx)
_, created, err := secret_service.CreateOrUpdateSecret(ctx, 0, repo.ID, ctx.PathParam("secretname"), opt.Data, opt.Description)
if err != nil {
@@ -346,7 +346,7 @@ func (Action) CreateVariable(ctx *context.APIContext) {
// "500":
// "$ref": "#/responses/error"
opt := web.GetForm(ctx).(*api.CreateVariableOption)
opt := web.GetForm[*api.CreateVariableOption](ctx)
repoID := ctx.Repo.Repository.ID
variableName := ctx.PathParam("variablename")
@@ -413,7 +413,7 @@ func (Action) UpdateVariable(ctx *context.APIContext) {
// "404":
// "$ref": "#/responses/notFound"
opt := web.GetForm(ctx).(*api.UpdateVariableOption)
opt := web.GetForm[*api.UpdateVariableOption](ctx)
v, err := actions_service.GetVariable(ctx, actions_model.FindVariablesOpts{
RepoID: ctx.Repo.Repository.ID,
@@ -1170,7 +1170,7 @@ func ActionsDispatchWorkflow(ctx *context.APIContext) {
// "$ref": "#/responses/validationError"
workflowID := ctx.PathParam("workflow_id")
opt := web.GetForm(ctx).(*api.CreateActionWorkflowDispatch)
opt := web.GetForm[*api.CreateActionWorkflowDispatch](ctx)
if opt.Ref == "" {
ctx.APIError(http.StatusUnprocessableEntity, "ref is required parameter")
return
+1 -1
View File
@@ -40,7 +40,7 @@ func UpdateAvatar(ctx *context.APIContext) {
// "$ref": "#/responses/empty"
// "404":
// "$ref": "#/responses/notFound"
form := web.GetForm(ctx).(*api.UpdateRepoAvatarOption)
form := web.GetForm[*api.UpdateRepoAvatarOption](ctx)
content, err := base64.StdEncoding.DecodeString(form.Image)
if err != nil {

Some files were not shown because too many files have changed in this diff Show More