mirror of
https://github.com/go-gitea/gitea.git
synced 2026-08-10 05:24:18 +09:00
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:
@@ -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:
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
|
||||
Vendored
+1
-1
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
}).
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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()))
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)))
|
||||
|
||||
@@ -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":
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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}
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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"))
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user