diff --git a/.golangci.yml b/.golangci.yml
index 819dead018..32d133aa09 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -11,6 +11,7 @@ linters:
- dupl
- errcheck
- forbidigo
+ - forcetypeassert
- gocheckcompilerdirectives
- gocritic
- govet
diff --git a/cmd/admin_auth_ldap.go b/cmd/admin_auth_ldap.go
index d3266fa48d..960535365b 100644
--- a/cmd/admin_auth_ldap.go
+++ b/cmd/admin_auth_ldap.go
@@ -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
}
diff --git a/cmd/admin_auth_oauth.go b/cmd/admin_auth_oauth.go
index c4a86191a1..f44327d262 100644
--- a/cmd/admin_auth_oauth.go
+++ b/cmd/admin_auth_oauth.go
@@ -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")
diff --git a/cmd/admin_auth_smtp.go b/cmd/admin_auth_smtp.go
index b7c1a8807e..5d99b5e1c5 100644
--- a/cmd/admin_auth_smtp.go
+++ b/cmd/admin_auth_smtp.go
@@ -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
diff --git a/modelmigration/v1_14/v156.go b/modelmigration/v1_14/v156.go
index 4f66bbf118..ac2828c0cf 100644
--- a/modelmigration/v1_14/v156.go
+++ b/modelmigration/v1_14/v156.go
@@ -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)
diff --git a/modelmigration/v1_8/v76.go b/modelmigration/v1_8/v76.go
index d666dcef49..d90a850763 100644
--- a/modelmigration/v1_8/v76.go
+++ b/modelmigration/v1_8/v76.go
@@ -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 {
diff --git a/models/asymkey/ssh_key_authorized_keys.go b/models/asymkey/ssh_key_authorized_keys.go
index 8eb5d24c82..1a45f5c439 100644
--- a/models/asymkey/ssh_key_authorized_keys.go
+++ b/models/asymkey/ssh_key_authorized_keys.go
@@ -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
}
diff --git a/models/auth/source.go b/models/auth/source.go
index 278898e49d..9bd6ce71f3 100644
--- a/models/auth/source.go
+++ b/models/auth/source.go
@@ -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)
}
diff --git a/models/db/context_test.go b/models/db/context_test.go
index 7804a15d1a..c409f5bbda 100644
--- a/models/db/context_test.go
+++ b/models/db/context_test.go
@@ -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" ...
diff --git a/models/db/error.go b/models/db/error.go
index e44886dcd7..b030c5ba78 100644
--- a/models/db/error.go
+++ b/models/db/error.go
@@ -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
}
diff --git a/models/packages/descriptor.go b/models/packages/descriptor.go
index b5b8634846..e3aef90a8b 100644
--- a/models/packages/descriptor.go
+++ b/models/packages/descriptor.go
@@ -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())
diff --git a/models/repo/repo_unit.go b/models/repo/repo_unit.go
index 5de5b6e4f3..dd4328648b 100644
--- a/models/repo/repo_unit.go
+++ b/models/repo/repo_unit.go
@@ -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) {
diff --git a/models/unittest/fixtures_loader.go b/models/unittest/fixtures_loader.go
index 7ad3bc9058..46c79fef1a 100644
--- a/models/unittest/fixtures_loader.go
+++ b/models/unittest/fixtures_loader.go
@@ -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
}
diff --git a/modules/actions/scoped_workflows.go b/modules/actions/scoped_workflows.go
index 3e3cd47da9..376faecace 100644
--- a/modules/actions/scoped_workflows.go
+++ b/modules/actions/scoped_workflows.go
@@ -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:
diff --git a/modules/actions/workflows.go b/modules/actions/workflows.go
index 87fa51de33..6b26840043 100644
--- a/modules/actions/workflows.go
+++ b/modules/actions/workflows.go
@@ -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
}
}
diff --git a/modules/assetfs/embed_test.go b/modules/assetfs/embed_test.go
index 06598da4c4..5c3db3672e 100644
--- a/modules/assetfs/embed_test.go
+++ b/modules/assetfs/embed_test.go
@@ -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)
diff --git a/modules/base/tool.go b/modules/base/tool.go
index bab2c57e95..1e4db2b977 100644
--- a/modules/base/tool.go
+++ b/modules/base/tool.go
@@ -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))
diff --git a/modules/cache/context_test.go b/modules/cache/context_test.go
index 1eee11836e..dc27f32ea9 100644
--- a/modules/cache/context_test.go
+++ b/modules/cache/context_test.go
@@ -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
diff --git a/modules/git/commit_info_gogit.go b/modules/git/commit_info_gogit.go
index 7c578580c8..13ad029cc5 100644
--- a/modules/git/commit_info_gogit.go
+++ b/modules/git/commit_info_gogit.go
@@ -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()
diff --git a/modules/git/repo_tag.go b/modules/git/repo_tag.go
index dde15602bb..871a3db68e 100644
--- a/modules/git/repo_tag.go
+++ b/modules/git/repo_tag.go
@@ -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
}).
diff --git a/modules/glob/glob_test.go b/modules/glob/glob_test.go
index 8467895252..0eb101fa14 100644
--- a/modules/glob/glob_test.go
+++ b/modules/glob/glob_test.go
@@ -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)
}
}
diff --git a/modules/globallock/globallock_test.go b/modules/globallock/globallock_test.go
index e6cedb67c0..39f58848a4 100644
--- a/modules/globallock/globallock_test.go
+++ b/modules/globallock/globallock_test.go
@@ -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()))
diff --git a/modules/globallock/locker_test.go b/modules/globallock/locker_test.go
index 1ade24dfa9..6f186fae9d 100644
--- a/modules/globallock/locker_test.go
+++ b/modules/globallock/locker_test.go
@@ -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.
diff --git a/modules/globallock/redis_locker.go b/modules/globallock/redis_locker.go
index 6c9fa80a7f..1883b3bb52 100644
--- a/modules/globallock/redis_locker.go
+++ b/modules/globallock/redis_locker.go
@@ -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,
diff --git a/modules/graceful/net_unix.go b/modules/graceful/net_unix.go
index 048cb99378..6650090f18 100644
--- a/modules/graceful/net_unix.go
+++ b/modules/graceful/net_unix.go
@@ -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)
}
diff --git a/modules/graceful/restart_unix.go b/modules/graceful/restart_unix.go
index 98d5c5cc20..831bebab92 100644
--- a/modules/graceful/restart_unix.go
+++ b/modules/graceful/restart_unix.go
@@ -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
}
diff --git a/modules/graceful/server.go b/modules/graceful/server.go
index 4cd138458f..a12b5aefcb 100644
--- a/modules/graceful/server.go
+++ b/modules/graceful/server.go
@@ -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 {
diff --git a/modules/gtprof/trace_builtin.go b/modules/gtprof/trace_builtin.go
index 76b2dae4b0..23fd82be9c 100644
--- a/modules/gtprof/trace_builtin.go
+++ b/modules/gtprof/trace_builtin.go
@@ -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)
}
}
diff --git a/modules/gtprof/trace_test.go b/modules/gtprof/trace_test.go
index 0f4e3facba..25bfddcb73 100644
--- a/modules/gtprof/trace_test.go
+++ b/modules/gtprof/trace_test.go
@@ -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",
diff --git a/modules/indexer/code/bleve/bleve.go b/modules/indexer/code/bleve/bleve.go
index a5f326cd06..6e78e42efb 100644
--- a/modules/indexer/code/bleve/bleve.go
+++ b/modules/indexer/code/bleve/bleve.go
@@ -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),
diff --git a/modules/indexer/code/elasticsearch/elasticsearch.go b/modules/indexer/code/elasticsearch/elasticsearch.go
index c0b20735b1..74d749cd1d 100644
--- a/modules/indexer/code/elasticsearch/elasticsearch.go
+++ b/modules/indexer/code/elasticsearch/elasticsearch.go
@@ -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 and 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,
diff --git a/modules/log/event_writer_conn.go b/modules/log/event_writer_conn.go
index 022206aa4d..fcb18bc14f 100644
--- a/modules/log/event_writer_conn.go
+++ b/modules/log/event_writer_conn.go
@@ -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,
diff --git a/modules/log/event_writer_console.go b/modules/log/event_writer_console.go
index 8a3e43710a..778ec1dc46 100644
--- a/modules/log/event_writer_console.go
+++ b/modules/log/event_writer_console.go
@@ -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 {
diff --git a/modules/log/event_writer_file.go b/modules/log/event_writer_file.go
index c4b8183c2a..5584657f61 100644
--- a/modules/log/event_writer_file.go
+++ b/modules/log/event_writer_file.go
@@ -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,
diff --git a/modules/log/manager_test.go b/modules/log/manager_test.go
index beddbccb73..59e5496bfa 100644
--- a/modules/log/manager_test.go
+++ b/modules/log/manager_test.go
@@ -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)
}
diff --git a/modules/markup/common/footnote.go b/modules/markup/common/footnote.go
index e552a28237..2c47ea1385 100644
--- a/modules/markup/common/footnote.go
+++ b/modules/markup/common/footnote.go
@@ -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(`