Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -245,19 +245,25 @@ require (
github.com/prometheus/common v0.63.0 // indirect
github.com/prometheus/procfs v0.16.1 // indirect
github.com/rhysd/actionlint v1.7.7 // indirect
github.com/richardlehane/mscfb v1.0.4 // indirect
github.com/richardlehane/msoleps v1.0.4 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rs/xid v1.6.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/skeema/knownhosts v1.3.1 // indirect
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
github.com/tiendc/go-deepcopy v1.6.0 // indirect
github.com/unknwon/com v1.0.1 // indirect
github.com/valyala/fastjson v1.6.4 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
github.com/xuri/efp v0.0.1 // indirect
github.com/xuri/excelize/v2 v2.9.1 // indirect
github.com/xuri/nfp v0.0.1 // indirect
github.com/zeebo/assert v1.3.0 // indirect
github.com/zeebo/blake3 v0.2.4 // indirect
go.etcd.io/bbolt v1.4.0 // indirect
Expand Down
13 changes: 13 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,11 @@ github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6O
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rhysd/actionlint v1.7.7 h1:0KgkoNTrYY7vmOCs9BW2AHxLvvpoY9nEUzgBHiPUr0k=
github.com/rhysd/actionlint v1.7.7/go.mod h1:AE6I6vJEkNaIfWqC2GNE5spIJNhxf8NCtLEKU4NnUXg=
github.com/richardlehane/mscfb v1.0.4 h1:WULscsljNPConisD5hR0+OyZjwK46Pfyr6mPu5ZawpM=
github.com/richardlehane/mscfb v1.0.4/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk=
github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
github.com/richardlehane/msoleps v1.0.4 h1:WuESlvhX3gH2IHcd8UqyCuFY5yiq/GR/yqaSM/9/g00=
github.com/richardlehane/msoleps v1.0.4/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
Expand Down Expand Up @@ -678,6 +683,8 @@ github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203 h1:QVqDTf3h2WHt08Yu
github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203/go.mod h1:oqN97ltKNihBbwlX8dLpwxCl3+HnXKV/R0e+sRLd9C8=
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
github.com/tiendc/go-deepcopy v1.6.0 h1:0UtfV/imoCwlLxVsyfUd4hNHnB3drXsfle+wzSCA5Wo=
github.com/tiendc/go-deepcopy v1.6.0/go.mod h1:toXoeQoUqXOOS/X4sKuiAoSk6elIdqc0pN7MTgOOo2I=
github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
github.com/tstranex/u2f v1.0.0 h1:HhJkSzDDlVSVIVt7pDJwCHQj67k7A5EeBgPmeD+pVsQ=
github.com/tstranex/u2f v1.0.0/go.mod h1:eahSLaqAS0zsIEv80+vXT7WanXs7MQQDg3j3wGBSayo=
Expand Down Expand Up @@ -711,6 +718,12 @@ github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQ
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/xuri/efp v0.0.1 h1:fws5Rv3myXyYni8uwj2qKjVaRP30PdjeYe2Y6FDsCL8=
github.com/xuri/efp v0.0.1/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
github.com/xuri/excelize/v2 v2.9.1 h1:VdSGk+rraGmgLHGFaGG9/9IWu1nj4ufjJ7uwMDtj8Qw=
github.com/xuri/excelize/v2 v2.9.1/go.mod h1:x7L6pKz2dvo9ejrRuD8Lnl98z4JLt0TGAwjhW+EiP8s=
github.com/xuri/nfp v0.0.1 h1:MDamSGatIvp8uOmDP8FnmjuQpu90NzdJxo7242ANR9Q=
github.com/xuri/nfp v0.0.1/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
github.com/yohcop/openid-go v1.0.1 h1:DPRd3iPO5F6O5zX2e62XpVAbPT6wV51cuucH0z9g3js=
Expand Down
1 change: 1 addition & 0 deletions options/locale/locale_en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -3539,6 +3539,7 @@ review_dismissed_reason = Reason:
create_branch = created branch <a href="%[2]s">%[3]s</a> in <a href="%[1]s">%[4]s</a>
starred_repo = starred <a href="%[1]s">%[2]s</a>
watched_repo = started watching <a href="%[1]s">%[2]s</a>
export_to_excel = Export to Excel

[tool]
now = now
Expand Down
39 changes: 30 additions & 9 deletions routers/web/repo/issue_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
shared_user "code.gitea.io/gitea/routers/web/shared/user"
"code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/convert"
"code.gitea.io/gitea/services/export"
issue_service "code.gitea.io/gitea/services/issue"
pull_service "code.gitea.io/gitea/services/pull"
)
Expand Down Expand Up @@ -258,14 +259,13 @@
return user.ID
}

// SearchRepoIssuesJSON lists the issues of a repository
// This function was copied from API (decouple the web and API routes),
// it is only used by frontend to search some dependency or related issues
func SearchRepoIssuesJSON(ctx *context.Context) {
func SearchRepoIssues(ctx *context.Context) (issues_model.IssueList, int64) {
before, since, err := context.GetQueryBeforeSince(ctx.Base)
if err != nil {
ctx.HTTPError(http.StatusUnprocessableEntity, err.Error())
return
return nil, 0
}

var isClosed optional.Option[bool]
Expand Down Expand Up @@ -295,7 +295,7 @@
}
if !issues_model.IsErrMilestoneNotExist(err) {
ctx.HTTPError(http.StatusInternalServerError, err.Error())
return
return nil, 0
}
id, err := strconv.ParseInt(part[i], 10, 64)
if err != nil {
Expand Down Expand Up @@ -329,15 +329,15 @@
// FIXME: we should be more efficient here
createdByID := getUserIDForFilter(ctx, "created_by")
if ctx.Written() {
return
return nil, 0
}
assignedByID := getUserIDForFilter(ctx, "assigned_by")
if ctx.Written() {
return
return nil, 0
}
mentionedByID := getUserIDForFilter(ctx, "mentioned_by")
if ctx.Written() {
return
return nil, 0
}

searchOpt := &issue_indexer.SearchOptions{
Expand Down Expand Up @@ -380,18 +380,39 @@
ids, total, err := issue_indexer.SearchIssues(ctx, searchOpt)
if err != nil {
ctx.HTTPError(http.StatusInternalServerError, "SearchIssues", err.Error())
return
return nil, 0
}
issues, err := issues_model.GetIssuesByIDs(ctx, ids, true)
if err != nil {
ctx.HTTPError(http.StatusInternalServerError, "FindIssuesByIDs", err.Error())
return
return nil, 0
}

return issues, total
}

// SearchRepoIssuesJSON lists the issues of a repository
func SearchRepoIssuesJSON(ctx *context.Context) {
issues, total := SearchRepoIssues(ctx)

ctx.SetTotalCountHeader(total)
ctx.JSON(http.StatusOK, convert.ToIssueList(ctx, ctx.Doer, issues))
}

func ExportIssues(ctx *context.Context) {
issues, total := SearchRepoIssues(ctx)

if total == 0 {
return
}

f := export.IssuesToExcel(ctx, issues)

ctx.Resp.Header().Set("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")

Check failure on line 411 in routers/web/repo/issue_list.go

View workflow job for this annotation

GitHub Actions / lint-backend

File is not properly formatted (gofmt)

Check failure on line 411 in routers/web/repo/issue_list.go

View workflow job for this annotation

GitHub Actions / lint-go-windows

File is not properly formatted (gofmt)

Check failure on line 411 in routers/web/repo/issue_list.go

View workflow job for this annotation

GitHub Actions / lint-go-gogit

File is not properly formatted (gofmt)
ctx.Resp.Header().Set("Content-Disposition", `attachment; filename="issues.xlsx"`)
_ = f.Write(ctx.Resp)
}

func BatchDeleteIssues(ctx *context.Context) {
issues := getActionIssues(ctx)
if ctx.Written() {
Expand Down
1 change: 1 addition & 0 deletions routers/web/web.go
Original file line number Diff line number Diff line change
Expand Up @@ -1237,6 +1237,7 @@ func registerWebRoutes(m *web.Router) {
m.Get("/choose", repo.NewIssueChooseTemplate)
})
m.Get("/search", repo.SearchRepoIssuesJSON)
m.Get("/export", reqRepoAdmin, repo.ExportIssues)
}, reqUnitIssuesReader)

addIssuesPullsUpdateRoutes := func() {
Expand Down
62 changes: 62 additions & 0 deletions services/export/excel.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package export

import (
"fmt"

Check failure on line 7 in services/export/excel.go

View workflow job for this annotation

GitHub Actions / lint-backend

File is not properly formatted (gofumpt)

Check failure on line 7 in services/export/excel.go

View workflow job for this annotation

GitHub Actions / lint-go-windows

File is not properly formatted (gofumpt)

Check failure on line 7 in services/export/excel.go

View workflow job for this annotation

GitHub Actions / lint-go-gogit

File is not properly formatted (gofumpt)
"github.com/xuri/excelize/v2"

issues_model "code.gitea.io/gitea/models/issues"
"code.gitea.io/gitea/services/context"
)

func IssuesToExcel(ctx *context.Context, issues issues_model.IssueList) *excelize.File {
f := excelize.NewFile()
sheet := f.GetSheetName(f.GetActiveSheetIndex())

headers := []string{"ID", "Title", "Status", "Assignee(s)", "Label(s)", "Created At"}
for col, h := range headers {
cell, _ := excelize.CoordinatesToCellName(col+1, 1)
f.SetCellValue(sheet, cell, h)

Check failure on line 21 in services/export/excel.go

View workflow job for this annotation

GitHub Actions / lint-backend

Error return value of `f.SetCellValue` is not checked (errcheck)

Check failure on line 21 in services/export/excel.go

View workflow job for this annotation

GitHub Actions / lint-go-windows

Error return value of `f.SetCellValue` is not checked (errcheck)

Check failure on line 21 in services/export/excel.go

View workflow job for this annotation

GitHub Actions / lint-go-gogit

Error return value of `f.SetCellValue` is not checked (errcheck)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ref: https://xuri.me/excelize/en/stream.html

Streaming write should be used here, as ordinary write will occupy a lot of memory when the data volume is slightly larger.

}

for i, issue := range issues {

Check failure on line 24 in services/export/excel.go

View workflow job for this annotation

GitHub Actions / lint-backend

empty-lines: extra empty line at the start of a block (revive)

Check failure on line 24 in services/export/excel.go

View workflow job for this annotation

GitHub Actions / lint-go-windows

empty-lines: extra empty line at the start of a block (revive)

Check failure on line 24 in services/export/excel.go

View workflow job for this annotation

GitHub Actions / lint-go-gogit

empty-lines: extra empty line at the start of a block (revive)

assignees := ""
if err := issue.LoadAssignees(ctx); err == nil {
if len(issue.Assignees) > 0 {
for _, assignee := range issue.Assignees {
if assignees != "" {
assignees += ", "
}
if assignee.FullName != "" {
assignees += assignee.FullName
} else {
assignees += assignee.Name
}
}
}
}

labels := ""
if err := issue.LoadLabels(ctx); err == nil {
if len(issue.Labels) > 0 {
for _, label := range issue.Labels {
if labels != "" {
labels += ", "
}
labels += label.Name
}
}
}

f.SetCellValue(sheet, fmt.Sprintf("A%d", i+2), issue.Index)

Check failure on line 54 in services/export/excel.go

View workflow job for this annotation

GitHub Actions / lint-backend

Error return value of `f.SetCellValue` is not checked (errcheck)

Check failure on line 54 in services/export/excel.go

View workflow job for this annotation

GitHub Actions / lint-go-windows

Error return value of `f.SetCellValue` is not checked (errcheck)

Check failure on line 54 in services/export/excel.go

View workflow job for this annotation

GitHub Actions / lint-go-gogit

Error return value of `f.SetCellValue` is not checked (errcheck)
f.SetCellValue(sheet, fmt.Sprintf("B%d", i+2), issue.Title)

Check failure on line 55 in services/export/excel.go

View workflow job for this annotation

GitHub Actions / lint-backend

Error return value of `f.SetCellValue` is not checked (errcheck)

Check failure on line 55 in services/export/excel.go

View workflow job for this annotation

GitHub Actions / lint-go-windows

Error return value of `f.SetCellValue` is not checked (errcheck)

Check failure on line 55 in services/export/excel.go

View workflow job for this annotation

GitHub Actions / lint-go-gogit

Error return value of `f.SetCellValue` is not checked (errcheck)
f.SetCellValue(sheet, fmt.Sprintf("C%d", i+2), issue.State())

Check failure on line 56 in services/export/excel.go

View workflow job for this annotation

GitHub Actions / lint-backend

Error return value of `f.SetCellValue` is not checked (errcheck)

Check failure on line 56 in services/export/excel.go

View workflow job for this annotation

GitHub Actions / lint-go-windows

Error return value of `f.SetCellValue` is not checked (errcheck)

Check failure on line 56 in services/export/excel.go

View workflow job for this annotation

GitHub Actions / lint-go-gogit

Error return value of `f.SetCellValue` is not checked (errcheck)
f.SetCellValue(sheet, fmt.Sprintf("D%d", i+2), assignees)

Check failure on line 57 in services/export/excel.go

View workflow job for this annotation

GitHub Actions / lint-backend

Error return value of `f.SetCellValue` is not checked (errcheck)

Check failure on line 57 in services/export/excel.go

View workflow job for this annotation

GitHub Actions / lint-go-windows

Error return value of `f.SetCellValue` is not checked (errcheck)

Check failure on line 57 in services/export/excel.go

View workflow job for this annotation

GitHub Actions / lint-go-gogit

Error return value of `f.SetCellValue` is not checked (errcheck)
f.SetCellValue(sheet, fmt.Sprintf("E%d", i+2), labels)

Check failure on line 58 in services/export/excel.go

View workflow job for this annotation

GitHub Actions / lint-backend

Error return value of `f.SetCellValue` is not checked (errcheck)

Check failure on line 58 in services/export/excel.go

View workflow job for this annotation

GitHub Actions / lint-go-windows

Error return value of `f.SetCellValue` is not checked (errcheck)

Check failure on line 58 in services/export/excel.go

View workflow job for this annotation

GitHub Actions / lint-go-gogit

Error return value of `f.SetCellValue` is not checked (errcheck)
f.SetCellValue(sheet, fmt.Sprintf("F%d", i+2), issue.CreatedUnix.AsTime()) // .Format("2006-01-02"))

Check failure on line 59 in services/export/excel.go

View workflow job for this annotation

GitHub Actions / lint-backend

Error return value of `f.SetCellValue` is not checked (errcheck)

Check failure on line 59 in services/export/excel.go

View workflow job for this annotation

GitHub Actions / lint-go-windows

Error return value of `f.SetCellValue` is not checked (errcheck)

Check failure on line 59 in services/export/excel.go

View workflow job for this annotation

GitHub Actions / lint-go-gogit

Error return value of `f.SetCellValue` is not checked (errcheck)
}
return f
}
1 change: 1 addition & 0 deletions templates/repo/issue/list.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
<a class="ui small primary small button issue-list-new{{if not .PullRequestCtx.Allowed}} disabled{{end}}" href="{{if .PullRequestCtx.Allowed}}{{.PullRequestCtx.BaseRepo.Link}}/compare/{{.PullRequestCtx.BaseRepo.DefaultBranch | PathEscapeSegments}}...{{if ne .Repository.Owner.Name .PullRequestCtx.BaseRepo.Owner.Name}}{{PathEscape .Repository.Owner.Name}}:{{end}}{{.Repository.DefaultBranch | PathEscapeSegments}}{{end}}">{{ctx.Locale.Tr "action.compare_commits_general"}}</a>
{{end}}
{{end}}
<a class="ui small primary button issue-list-export" href="{{.RepoLink}}/issues/export?{{.Page.GetParams}}">{{ctx.Locale.Tr "action.export_to_excel"}}</a>
</div>

{{template "repo/issue/filters" .}}
Expand Down
Loading