diff --git a/contrib/systemd/gitea.service b/contrib/systemd/gitea.service
index d205c6ee8ba6e..c091722a743be 100644
--- a/contrib/systemd/gitea.service
+++ b/contrib/systemd/gitea.service
@@ -1,6 +1,5 @@
[Unit]
Description=Gitea (Git with a cup of tea)
-After=syslog.target
After=network.target
###
# Don't forget to add the database service dependencies
diff --git a/models/actions/runner.go b/models/actions/runner.go
index b646146ee6728..67f003387b112 100644
--- a/models/actions/runner.go
+++ b/models/actions/runner.go
@@ -13,6 +13,7 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/shared/types"
user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/translation"
"code.gitea.io/gitea/modules/util"
@@ -159,7 +160,7 @@ type FindRunnerOptions struct {
OwnerID int64
Sort string
Filter string
- IsOnline util.OptionalBool
+ IsOnline optional.Option[bool]
WithAvailable bool // not only runners belong to, but also runners can be used
}
@@ -186,10 +187,12 @@ func (opts FindRunnerOptions) ToConds() builder.Cond {
cond = cond.And(builder.Like{"name", opts.Filter})
}
- if opts.IsOnline.IsTrue() {
- cond = cond.And(builder.Gt{"last_online": time.Now().Add(-RunnerOfflineTime).Unix()})
- } else if opts.IsOnline.IsFalse() {
- cond = cond.And(builder.Lte{"last_online": time.Now().Add(-RunnerOfflineTime).Unix()})
+ if opts.IsOnline.Has() {
+ if opts.IsOnline.Value() {
+ cond = cond.And(builder.Gt{"last_online": time.Now().Add(-RunnerOfflineTime).Unix()})
+ } else {
+ cond = cond.And(builder.Lte{"last_online": time.Now().Add(-RunnerOfflineTime).Unix()})
+ }
}
return cond
}
diff --git a/models/activities/action.go b/models/activities/action.go
index 15bd9a52acc5c..fcc97e387264d 100644
--- a/models/activities/action.go
+++ b/models/activities/action.go
@@ -225,8 +225,8 @@ func (a *Action) ShortActUserName(ctx context.Context) string {
return base.EllipsisString(a.GetActUserName(ctx), 20)
}
-// GetDisplayName gets the action's display name based on DEFAULT_SHOW_FULL_NAME, or falls back to the username if it is blank.
-func (a *Action) GetDisplayName(ctx context.Context) string {
+// GetActDisplayName gets the action's display name based on DEFAULT_SHOW_FULL_NAME, or falls back to the username if it is blank.
+func (a *Action) GetActDisplayName(ctx context.Context) string {
if setting.UI.DefaultShowFullName {
trimmedFullName := strings.TrimSpace(a.GetActFullName(ctx))
if len(trimmedFullName) > 0 {
@@ -236,8 +236,8 @@ func (a *Action) GetDisplayName(ctx context.Context) string {
return a.ShortActUserName(ctx)
}
-// GetDisplayNameTitle gets the action's display name used for the title (tooltip) based on DEFAULT_SHOW_FULL_NAME
-func (a *Action) GetDisplayNameTitle(ctx context.Context) string {
+// GetActDisplayNameTitle gets the action's display name used for the title (tooltip) based on DEFAULT_SHOW_FULL_NAME
+func (a *Action) GetActDisplayNameTitle(ctx context.Context) string {
if setting.UI.DefaultShowFullName {
return a.ShortActUserName(ctx)
}
diff --git a/models/auth/source.go b/models/auth/source.go
index 1bdde8235cdb4..f360ca98017d0 100644
--- a/models/auth/source.go
+++ b/models/auth/source.go
@@ -11,6 +11,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
@@ -243,14 +244,14 @@ func CreateSource(ctx context.Context, source *Source) error {
type FindSourcesOptions struct {
db.ListOptions
- IsActive util.OptionalBool
+ IsActive optional.Option[bool]
LoginType Type
}
func (opts FindSourcesOptions) ToConds() builder.Cond {
conds := builder.NewCond()
- if !opts.IsActive.IsNone() {
- conds = conds.And(builder.Eq{"is_active": opts.IsActive.IsTrue()})
+ if opts.IsActive.Has() {
+ conds = conds.And(builder.Eq{"is_active": opts.IsActive.Value()})
}
if opts.LoginType != NoType {
conds = conds.And(builder.Eq{"`type`": opts.LoginType})
@@ -262,7 +263,7 @@ func (opts FindSourcesOptions) ToConds() builder.Cond {
// source of type LoginSSPI
func IsSSPIEnabled(ctx context.Context) bool {
exist, err := db.Exist[Source](ctx, FindSourcesOptions{
- IsActive: util.OptionalBoolTrue,
+ IsActive: optional.Some(true),
LoginType: SSPI,
}.ToConds())
if err != nil {
diff --git a/models/fixtures/action_run.yml b/models/fixtures/action_run.yml
index 2c2151f354af6..a42ab77ca5b09 100644
--- a/models/fixtures/action_run.yml
+++ b/models/fixtures/action_run.yml
@@ -17,3 +17,22 @@
updated: 1683636626
need_approval: 0
approved_by: 0
+-
+ id: 792
+ title: "update actions"
+ repo_id: 4
+ owner_id: 1
+ workflow_id: "artifact.yaml"
+ index: 188
+ trigger_user_id: 1
+ ref: "refs/heads/master"
+ commit_sha: "c2d72f548424103f01ee1dc02889c1e2bff816b0"
+ event: "push"
+ is_fork_pull_request: 0
+ status: 1
+ started: 1683636528
+ stopped: 1683636626
+ created: 1683636108
+ updated: 1683636626
+ need_approval: 0
+ approved_by: 0
diff --git a/models/fixtures/action_run_job.yml b/models/fixtures/action_run_job.yml
index 071998b9796f9..fd90f4fd5d2ea 100644
--- a/models/fixtures/action_run_job.yml
+++ b/models/fixtures/action_run_job.yml
@@ -12,3 +12,17 @@
status: 1
started: 1683636528
stopped: 1683636626
+-
+ id: 193
+ run_id: 792
+ repo_id: 4
+ owner_id: 1
+ commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0
+ is_fork_pull_request: 0
+ name: job_2
+ attempt: 1
+ job_id: job_2
+ task_id: 48
+ status: 1
+ started: 1683636528
+ stopped: 1683636626
diff --git a/models/fixtures/action_task.yml b/models/fixtures/action_task.yml
index c78fb3c5d6377..443effe08c92a 100644
--- a/models/fixtures/action_task.yml
+++ b/models/fixtures/action_task.yml
@@ -18,3 +18,23 @@
log_length: 707
log_size: 90179
log_expired: 0
+-
+ id: 48
+ job_id: 193
+ attempt: 1
+ runner_id: 1
+ status: 6 # 6 is the status code for "running", running task can upload artifacts
+ started: 1683636528
+ stopped: 1683636626
+ repo_id: 4
+ owner_id: 1
+ commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0
+ is_fork_pull_request: 0
+ token_hash: ffffcfffffffbffffffffffffffffefffffffafffffffffffffffffffffffffffffdffffffffffffffffffffffffffffffff
+ token_salt: ffffffffff
+ token_last_eight: ffffffff
+ log_filename: artifact-test2/2f/47.log
+ log_in_storage: 1
+ log_length: 707
+ log_size: 90179
+ log_expired: 0
diff --git a/models/issues/comment.go b/models/issues/comment.go
index da91a83384ec2..e37f844b5c7d2 100644
--- a/models/issues/comment.go
+++ b/models/issues/comment.go
@@ -22,6 +22,7 @@ import (
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/references"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil"
@@ -1036,8 +1037,8 @@ type FindCommentsOptions struct {
TreePath string
Type CommentType
IssueIDs []int64
- Invalidated util.OptionalBool
- IsPull util.OptionalBool
+ Invalidated optional.Option[bool]
+ IsPull optional.Option[bool]
}
// ToConds implements FindOptions interface
@@ -1069,11 +1070,11 @@ func (opts FindCommentsOptions) ToConds() builder.Cond {
if len(opts.TreePath) > 0 {
cond = cond.And(builder.Eq{"comment.tree_path": opts.TreePath})
}
- if !opts.Invalidated.IsNone() {
- cond = cond.And(builder.Eq{"comment.invalidated": opts.Invalidated.IsTrue()})
+ if opts.Invalidated.Has() {
+ cond = cond.And(builder.Eq{"comment.invalidated": opts.Invalidated.Value()})
}
- if opts.IsPull != util.OptionalBoolNone {
- cond = cond.And(builder.Eq{"issue.is_pull": opts.IsPull.IsTrue()})
+ if opts.IsPull.Has() {
+ cond = cond.And(builder.Eq{"issue.is_pull": opts.IsPull.Value()})
}
return cond
}
@@ -1082,7 +1083,7 @@ func (opts FindCommentsOptions) ToConds() builder.Cond {
func FindComments(ctx context.Context, opts *FindCommentsOptions) (CommentList, error) {
comments := make([]*Comment, 0, 10)
sess := db.GetEngine(ctx).Where(opts.ToConds())
- if opts.RepoID > 0 || opts.IsPull != util.OptionalBoolNone {
+ if opts.RepoID > 0 || opts.IsPull.Has() {
sess.Join("INNER", "issue", "issue.id = comment.issue_id")
}
diff --git a/models/issues/issue_search.go b/models/issues/issue_search.go
index 7dc277327a89c..c5c9cecdb92d6 100644
--- a/models/issues/issue_search.go
+++ b/models/issues/issue_search.go
@@ -13,7 +13,7 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
- "code.gitea.io/gitea/modules/util"
+ "code.gitea.io/gitea/modules/optional"
"xorm.io/builder"
"xorm.io/xorm"
@@ -34,8 +34,8 @@ type IssuesOptions struct { //nolint
MilestoneIDs []int64
ProjectID int64
ProjectBoardID int64
- IsClosed util.OptionalBool
- IsPull util.OptionalBool
+ IsClosed optional.Option[bool]
+ IsPull optional.Option[bool]
LabelIDs []int64
IncludedLabelNames []string
ExcludedLabelNames []string
@@ -46,7 +46,7 @@ type IssuesOptions struct { //nolint
UpdatedBeforeUnix int64
// prioritize issues from this repo
PriorityRepoID int64
- IsArchived util.OptionalBool
+ IsArchived optional.Option[bool]
Org *organization.Organization // issues permission scope
Team *organization.Team // issues permission scope
User *user_model.User // issues permission scope
@@ -217,8 +217,8 @@ func applyConditions(sess *xorm.Session, opts *IssuesOptions) *xorm.Session {
applyRepoConditions(sess, opts)
- if !opts.IsClosed.IsNone() {
- sess.And("issue.is_closed=?", opts.IsClosed.IsTrue())
+ if opts.IsClosed.Has() {
+ sess.And("issue.is_closed=?", opts.IsClosed.Value())
}
if opts.AssigneeID > 0 {
@@ -260,21 +260,18 @@ func applyConditions(sess *xorm.Session, opts *IssuesOptions) *xorm.Session {
applyProjectBoardCondition(sess, opts)
- switch opts.IsPull {
- case util.OptionalBoolTrue:
- sess.And("issue.is_pull=?", true)
- case util.OptionalBoolFalse:
- sess.And("issue.is_pull=?", false)
+ if opts.IsPull.Has() {
+ sess.And("issue.is_pull=?", opts.IsPull.Value())
}
- if opts.IsArchived != util.OptionalBoolNone {
- sess.And(builder.Eq{"repository.is_archived": opts.IsArchived.IsTrue()})
+ if opts.IsArchived.Has() {
+ sess.And(builder.Eq{"repository.is_archived": opts.IsArchived.Value()})
}
applyLabelsCondition(sess, opts)
if opts.User != nil {
- sess.And(issuePullAccessibleRepoCond("issue.repo_id", opts.User.ID, opts.Org, opts.Team, opts.IsPull.IsTrue()))
+ sess.And(issuePullAccessibleRepoCond("issue.repo_id", opts.User.ID, opts.Org, opts.Team, opts.IsPull.Value()))
}
return sess
diff --git a/models/issues/issue_stats.go b/models/issues/issue_stats.go
index 99ca19f8044b8..32c5674fc925a 100644
--- a/models/issues/issue_stats.go
+++ b/models/issues/issue_stats.go
@@ -8,7 +8,6 @@ import (
"fmt"
"code.gitea.io/gitea/models/db"
- "code.gitea.io/gitea/modules/util"
"xorm.io/builder"
"xorm.io/xorm"
@@ -170,11 +169,8 @@ func applyIssuesOptions(sess *xorm.Session, opts *IssuesOptions, issueIDs []int6
applyReviewedCondition(sess, opts.ReviewedID)
}
- switch opts.IsPull {
- case util.OptionalBoolTrue:
- sess.And("issue.is_pull=?", true)
- case util.OptionalBoolFalse:
- sess.And("issue.is_pull=?", false)
+ if opts.IsPull.Has() {
+ sess.And("issue.is_pull=?", opts.IsPull.Value())
}
return sess
diff --git a/models/issues/label.go b/models/issues/label.go
index 527d8d7853289..f6ecc68cd1804 100644
--- a/models/issues/label.go
+++ b/models/issues/label.go
@@ -12,6 +12,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/label"
+ "code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
@@ -126,7 +127,7 @@ func (l *Label) CalOpenOrgIssues(ctx context.Context, repoID, labelID int64) {
counts, _ := CountIssuesByRepo(ctx, &IssuesOptions{
RepoIDs: []int64{repoID},
LabelIDs: []int64{labelID},
- IsClosed: util.OptionalBoolFalse,
+ IsClosed: optional.Some(false),
})
for _, count := range counts {
diff --git a/models/issues/milestone.go b/models/issues/milestone.go
index ea52a64c81be8..db0312adf0057 100644
--- a/models/issues/milestone.go
+++ b/models/issues/milestone.go
@@ -11,6 +11,7 @@ import (
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
+ "code.gitea.io/gitea/modules/optional"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
@@ -302,7 +303,7 @@ func DeleteMilestoneByRepoID(ctx context.Context, repoID, id int64) error {
}
numClosedMilestones, err := db.Count[Milestone](ctx, FindMilestoneOptions{
RepoID: repo.ID,
- IsClosed: util.OptionalBoolTrue,
+ IsClosed: optional.Some(true),
})
if err != nil {
return err
diff --git a/models/issues/milestone_list.go b/models/issues/milestone_list.go
index a73bf73c17c9f..d1b3f0301b580 100644
--- a/models/issues/milestone_list.go
+++ b/models/issues/milestone_list.go
@@ -8,7 +8,7 @@ import (
"strings"
"code.gitea.io/gitea/models/db"
- "code.gitea.io/gitea/modules/util"
+ "code.gitea.io/gitea/modules/optional"
"xorm.io/builder"
)
@@ -28,7 +28,7 @@ func (milestones MilestoneList) getMilestoneIDs() []int64 {
type FindMilestoneOptions struct {
db.ListOptions
RepoID int64
- IsClosed util.OptionalBool
+ IsClosed optional.Option[bool]
Name string
SortType string
RepoCond builder.Cond
@@ -40,8 +40,8 @@ func (opts FindMilestoneOptions) ToConds() builder.Cond {
if opts.RepoID != 0 {
cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
}
- if opts.IsClosed != util.OptionalBoolNone {
- cond = cond.And(builder.Eq{"is_closed": opts.IsClosed.IsTrue()})
+ if opts.IsClosed.Has() {
+ cond = cond.And(builder.Eq{"is_closed": opts.IsClosed.Value()})
}
if opts.RepoCond != nil && opts.RepoCond.IsValid() {
cond = cond.And(builder.In("repo_id", builder.Select("id").From("repository").Where(opts.RepoCond)))
diff --git a/models/issues/milestone_test.go b/models/issues/milestone_test.go
index 7477af92c8c49..e5f6f15ca2a29 100644
--- a/models/issues/milestone_test.go
+++ b/models/issues/milestone_test.go
@@ -11,10 +11,10 @@ import (
issues_model "code.gitea.io/gitea/models/issues"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
+ "code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil"
- "code.gitea.io/gitea/modules/util"
"github.com/stretchr/testify/assert"
)
@@ -39,10 +39,10 @@ func TestGetMilestoneByRepoID(t *testing.T) {
func TestGetMilestonesByRepoID(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
test := func(repoID int64, state api.StateType) {
- var isClosed util.OptionalBool
+ var isClosed optional.Option[bool]
switch state {
case api.StateClosed, api.StateOpen:
- isClosed = util.OptionalBoolOf(state == api.StateClosed)
+ isClosed = optional.Some(state == api.StateClosed)
}
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID})
milestones, err := db.Find[issues_model.Milestone](db.DefaultContext, issues_model.FindMilestoneOptions{
@@ -84,7 +84,7 @@ func TestGetMilestonesByRepoID(t *testing.T) {
milestones, err := db.Find[issues_model.Milestone](db.DefaultContext, issues_model.FindMilestoneOptions{
RepoID: unittest.NonexistentID,
- IsClosed: util.OptionalBoolFalse,
+ IsClosed: optional.Some(false),
})
assert.NoError(t, err)
assert.Len(t, milestones, 0)
@@ -101,7 +101,7 @@ func TestGetMilestones(t *testing.T) {
PageSize: setting.UI.IssuePagingNum,
},
RepoID: repo.ID,
- IsClosed: util.OptionalBoolFalse,
+ IsClosed: optional.Some(false),
SortType: sortType,
})
assert.NoError(t, err)
@@ -118,7 +118,7 @@ func TestGetMilestones(t *testing.T) {
PageSize: setting.UI.IssuePagingNum,
},
RepoID: repo.ID,
- IsClosed: util.OptionalBoolTrue,
+ IsClosed: optional.Some(true),
Name: "",
SortType: sortType,
})
@@ -178,7 +178,7 @@ func TestCountRepoClosedMilestones(t *testing.T) {
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID})
count, err := db.Count[issues_model.Milestone](db.DefaultContext, issues_model.FindMilestoneOptions{
RepoID: repoID,
- IsClosed: util.OptionalBoolTrue,
+ IsClosed: optional.Some(true),
})
assert.NoError(t, err)
assert.EqualValues(t, repo.NumClosedMilestones, count)
@@ -189,7 +189,7 @@ func TestCountRepoClosedMilestones(t *testing.T) {
count, err := db.Count[issues_model.Milestone](db.DefaultContext, issues_model.FindMilestoneOptions{
RepoID: unittest.NonexistentID,
- IsClosed: util.OptionalBoolTrue,
+ IsClosed: optional.Some(true),
})
assert.NoError(t, err)
assert.EqualValues(t, 0, count)
@@ -206,7 +206,7 @@ func TestCountMilestonesByRepoIDs(t *testing.T) {
openCounts, err := issues_model.CountMilestonesMap(db.DefaultContext, issues_model.FindMilestoneOptions{
RepoIDs: []int64{1, 2},
- IsClosed: util.OptionalBoolFalse,
+ IsClosed: optional.Some(false),
})
assert.NoError(t, err)
assert.EqualValues(t, repo1OpenCount, openCounts[1])
@@ -215,7 +215,7 @@ func TestCountMilestonesByRepoIDs(t *testing.T) {
closedCounts, err := issues_model.CountMilestonesMap(db.DefaultContext,
issues_model.FindMilestoneOptions{
RepoIDs: []int64{1, 2},
- IsClosed: util.OptionalBoolTrue,
+ IsClosed: optional.Some(true),
})
assert.NoError(t, err)
assert.EqualValues(t, repo1ClosedCount, closedCounts[1])
@@ -234,7 +234,7 @@ func TestGetMilestonesByRepoIDs(t *testing.T) {
PageSize: setting.UI.IssuePagingNum,
},
RepoIDs: []int64{repo1.ID, repo2.ID},
- IsClosed: util.OptionalBoolFalse,
+ IsClosed: optional.Some(false),
SortType: sortType,
})
assert.NoError(t, err)
@@ -252,7 +252,7 @@ func TestGetMilestonesByRepoIDs(t *testing.T) {
PageSize: setting.UI.IssuePagingNum,
},
RepoIDs: []int64{repo1.ID, repo2.ID},
- IsClosed: util.OptionalBoolTrue,
+ IsClosed: optional.Some(true),
SortType: sortType,
})
assert.NoError(t, err)
diff --git a/models/issues/review_list.go b/models/issues/review_list.go
index 282f18b4f7f65..ec6cb07988658 100644
--- a/models/issues/review_list.go
+++ b/models/issues/review_list.go
@@ -9,7 +9,7 @@ import (
"code.gitea.io/gitea/models/db"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/container"
- "code.gitea.io/gitea/modules/util"
+ "code.gitea.io/gitea/modules/optional"
"xorm.io/builder"
)
@@ -68,7 +68,7 @@ type FindReviewOptions struct {
IssueID int64
ReviewerID int64
OfficialOnly bool
- Dismissed util.OptionalBool
+ Dismissed optional.Option[bool]
}
func (opts *FindReviewOptions) toCond() builder.Cond {
@@ -85,8 +85,8 @@ func (opts *FindReviewOptions) toCond() builder.Cond {
if opts.OfficialOnly {
cond = cond.And(builder.Eq{"official": true})
}
- if !opts.Dismissed.IsNone() {
- cond = cond.And(builder.Eq{"dismissed": opts.Dismissed.IsTrue()})
+ if opts.Dismissed.Has() {
+ cond = cond.And(builder.Eq{"dismissed": opts.Dismissed.Value()})
}
return cond
}
diff --git a/models/issues/tracked_time.go b/models/issues/tracked_time.go
index 91c4832e497f9..4063ca043bd3d 100644
--- a/models/issues/tracked_time.go
+++ b/models/issues/tracked_time.go
@@ -11,6 +11,7 @@ import (
"code.gitea.io/gitea/models/db"
user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
@@ -340,7 +341,7 @@ func GetTrackedTimeByID(ctx context.Context, id int64) (*TrackedTime, error) {
}
// GetIssueTotalTrackedTime returns the total tracked time for issues by given conditions.
-func GetIssueTotalTrackedTime(ctx context.Context, opts *IssuesOptions, isClosed util.OptionalBool) (int64, error) {
+func GetIssueTotalTrackedTime(ctx context.Context, opts *IssuesOptions, isClosed optional.Option[bool]) (int64, error) {
if len(opts.IssueIDs) <= MaxQueryParameters {
return getIssueTotalTrackedTimeChunk(ctx, opts, isClosed, opts.IssueIDs)
}
@@ -363,7 +364,7 @@ func GetIssueTotalTrackedTime(ctx context.Context, opts *IssuesOptions, isClosed
return accum, nil
}
-func getIssueTotalTrackedTimeChunk(ctx context.Context, opts *IssuesOptions, isClosed util.OptionalBool, issueIDs []int64) (int64, error) {
+func getIssueTotalTrackedTimeChunk(ctx context.Context, opts *IssuesOptions, isClosed optional.Option[bool], issueIDs []int64) (int64, error) {
sumSession := func(opts *IssuesOptions, issueIDs []int64) *xorm.Session {
sess := db.GetEngine(ctx).
Table("tracked_time").
@@ -378,8 +379,8 @@ func getIssueTotalTrackedTimeChunk(ctx context.Context, opts *IssuesOptions, isC
}
session := sumSession(opts, issueIDs)
- if !isClosed.IsNone() {
- session = session.And("issue.is_closed = ?", isClosed.IsTrue())
+ if isClosed.Has() {
+ session = session.And("issue.is_closed = ?", isClosed.Value())
}
return session.SumInt(new(trackedTime), "tracked_time.time")
}
diff --git a/models/issues/tracked_time_test.go b/models/issues/tracked_time_test.go
index 9beb862ffbca2..d82bff967a980 100644
--- a/models/issues/tracked_time_test.go
+++ b/models/issues/tracked_time_test.go
@@ -11,7 +11,7 @@ import (
issues_model "code.gitea.io/gitea/models/issues"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
- "code.gitea.io/gitea/modules/util"
+ "code.gitea.io/gitea/modules/optional"
"github.com/stretchr/testify/assert"
)
@@ -120,15 +120,15 @@ func TestTotalTimesForEachUser(t *testing.T) {
func TestGetIssueTotalTrackedTime(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- ttt, err := issues_model.GetIssueTotalTrackedTime(db.DefaultContext, &issues_model.IssuesOptions{MilestoneIDs: []int64{1}}, util.OptionalBoolFalse)
+ ttt, err := issues_model.GetIssueTotalTrackedTime(db.DefaultContext, &issues_model.IssuesOptions{MilestoneIDs: []int64{1}}, optional.Some(false))
assert.NoError(t, err)
assert.EqualValues(t, 3682, ttt)
- ttt, err = issues_model.GetIssueTotalTrackedTime(db.DefaultContext, &issues_model.IssuesOptions{MilestoneIDs: []int64{1}}, util.OptionalBoolTrue)
+ ttt, err = issues_model.GetIssueTotalTrackedTime(db.DefaultContext, &issues_model.IssuesOptions{MilestoneIDs: []int64{1}}, optional.Some(true))
assert.NoError(t, err)
assert.EqualValues(t, 0, ttt)
- ttt, err = issues_model.GetIssueTotalTrackedTime(db.DefaultContext, &issues_model.IssuesOptions{MilestoneIDs: []int64{1}}, util.OptionalBoolNone)
+ ttt, err = issues_model.GetIssueTotalTrackedTime(db.DefaultContext, &issues_model.IssuesOptions{MilestoneIDs: []int64{1}}, optional.None[bool]())
assert.NoError(t, err)
assert.EqualValues(t, 3682, ttt)
}
diff --git a/models/packages/descriptor.go b/models/packages/descriptor.go
index f849ab5c0417c..b8ef698d3822a 100644
--- a/models/packages/descriptor.go
+++ b/models/packages/descriptor.go
@@ -70,16 +70,26 @@ type PackageFileDescriptor struct {
Properties PackagePropertyList
}
-// PackageWebLink returns the package web link
+// PackageWebLink returns the relative package web link
func (pd *PackageDescriptor) PackageWebLink() string {
return fmt.Sprintf("%s/-/packages/%s/%s", pd.Owner.HomeLink(), string(pd.Package.Type), url.PathEscape(pd.Package.LowerName))
}
-// FullWebLink returns the package version web link
-func (pd *PackageDescriptor) FullWebLink() string {
+// VersionWebLink returns the relative package version web link
+func (pd *PackageDescriptor) VersionWebLink() string {
return fmt.Sprintf("%s/%s", pd.PackageWebLink(), url.PathEscape(pd.Version.LowerVersion))
}
+// PackageHTMLURL returns the absolute package HTML URL
+func (pd *PackageDescriptor) PackageHTMLURL() string {
+ return fmt.Sprintf("%s/-/packages/%s/%s", pd.Owner.HTMLURL(), string(pd.Package.Type), url.PathEscape(pd.Package.LowerName))
+}
+
+// VersionHTMLURL returns the absolute package version HTML URL
+func (pd *PackageDescriptor) VersionHTMLURL() string {
+ return fmt.Sprintf("%s/%s", pd.PackageHTMLURL(), url.PathEscape(pd.Version.LowerVersion))
+}
+
// CalculateBlobSize returns the total blobs size in bytes
func (pd *PackageDescriptor) CalculateBlobSize() int64 {
size := int64(0)
diff --git a/models/packages/nuget/search.go b/models/packages/nuget/search.go
index 53cdf2d4ad89e..7a505ff08f3e5 100644
--- a/models/packages/nuget/search.go
+++ b/models/packages/nuget/search.go
@@ -55,7 +55,7 @@ func CountPackages(ctx context.Context, opts *packages_model.PackageSearchOption
func toConds(opts *packages_model.PackageSearchOptions) builder.Cond {
var cond builder.Cond = builder.Eq{
- "package.is_internal": opts.IsInternal.IsTrue(),
+ "package.is_internal": opts.IsInternal.Value(),
"package.owner_id": opts.OwnerID,
"package.type": packages_model.TypeNuGet,
}
diff --git a/models/packages/package_version.go b/models/packages/package_version.go
index 8fc475691bd0c..505dbaa0a576a 100644
--- a/models/packages/package_version.go
+++ b/models/packages/package_version.go
@@ -9,6 +9,7 @@ import (
"strings"
"code.gitea.io/gitea/models/db"
+ "code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
@@ -105,7 +106,7 @@ func getVersionByNameAndVersion(ctx context.Context, ownerID int64, packageType
ExactMatch: true,
Value: version,
},
- IsInternal: util.OptionalBoolOf(isInternal),
+ IsInternal: optional.Some(isInternal),
Paginator: db.NewAbsoluteListOptions(0, 1),
})
if err != nil {
@@ -122,7 +123,7 @@ func GetVersionsByPackageType(ctx context.Context, ownerID int64, packageType Ty
pvs, _, err := SearchVersions(ctx, &PackageSearchOptions{
OwnerID: ownerID,
Type: packageType,
- IsInternal: util.OptionalBoolFalse,
+ IsInternal: optional.Some(false),
})
return pvs, err
}
@@ -136,7 +137,7 @@ func GetVersionsByPackageName(ctx context.Context, ownerID int64, packageType Ty
ExactMatch: true,
Value: name,
},
- IsInternal: util.OptionalBoolFalse,
+ IsInternal: optional.Some(false),
})
return pvs, err
}
@@ -182,18 +183,18 @@ type PackageSearchOptions struct {
Name SearchValue // only results with the specific name are found
Version SearchValue // only results with the specific version are found
Properties map[string]string // only results are found which contain all listed version properties with the specific value
- IsInternal util.OptionalBool
- HasFileWithName string // only results are found which are associated with a file with the specific name
- HasFiles util.OptionalBool // only results are found which have associated files
+ IsInternal optional.Option[bool]
+ HasFileWithName string // only results are found which are associated with a file with the specific name
+ HasFiles optional.Option[bool] // only results are found which have associated files
Sort VersionSort
db.Paginator
}
func (opts *PackageSearchOptions) ToConds() builder.Cond {
cond := builder.NewCond()
- if !opts.IsInternal.IsNone() {
+ if opts.IsInternal.Has() {
cond = builder.Eq{
- "package_version.is_internal": opts.IsInternal.IsTrue(),
+ "package_version.is_internal": opts.IsInternal.Value(),
}
}
@@ -250,10 +251,10 @@ func (opts *PackageSearchOptions) ToConds() builder.Cond {
cond = cond.And(builder.Exists(builder.Select("package_file.id").From("package_file").Where(fileCond)))
}
- if !opts.HasFiles.IsNone() {
+ if opts.HasFiles.Has() {
filesCond := builder.Exists(builder.Select("package_file.id").From("package_file").Where(builder.Expr("package_file.version_id = package_version.id")))
- if opts.HasFiles.IsFalse() {
+ if !opts.HasFiles.Value() {
filesCond = builder.Not{filesCond}
}
@@ -307,8 +308,8 @@ func SearchLatestVersions(ctx context.Context, opts *PackageSearchOptions) ([]*P
And(builder.Expr("pv2.id IS NULL"))
joinCond := builder.Expr("package_version.package_id = pv2.package_id AND (package_version.created_unix < pv2.created_unix OR (package_version.created_unix = pv2.created_unix AND package_version.id < pv2.id))")
- if !opts.IsInternal.IsNone() {
- joinCond = joinCond.And(builder.Eq{"pv2.is_internal": opts.IsInternal.IsTrue()})
+ if opts.IsInternal.Has() {
+ joinCond = joinCond.And(builder.Eq{"pv2.is_internal": opts.IsInternal.Value()})
}
sess := db.GetEngine(ctx).
diff --git a/models/project/project.go b/models/project/project.go
index 42b06e58c93f1..8f9ee2a99e9c7 100644
--- a/models/project/project.go
+++ b/models/project/project.go
@@ -12,6 +12,7 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
@@ -196,7 +197,7 @@ type SearchOptions struct {
db.ListOptions
OwnerID int64
RepoID int64
- IsClosed util.OptionalBool
+ IsClosed optional.Option[bool]
OrderBy db.SearchOrderBy
Type Type
Title string
@@ -207,11 +208,8 @@ func (opts SearchOptions) ToConds() builder.Cond {
if opts.RepoID > 0 {
cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
}
- switch opts.IsClosed {
- case util.OptionalBoolTrue:
- cond = cond.And(builder.Eq{"is_closed": true})
- case util.OptionalBoolFalse:
- cond = cond.And(builder.Eq{"is_closed": false})
+ if opts.IsClosed.Has() {
+ cond = cond.And(builder.Eq{"is_closed": opts.IsClosed.Value()})
}
if opts.Type > 0 {
diff --git a/models/repo/repo.go b/models/repo/repo.go
index 13493ba6e80e6..5ce3ecb58aebc 100644
--- a/models/repo/repo.go
+++ b/models/repo/repo.go
@@ -20,6 +20,7 @@ import (
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/markup"
+ "code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil"
@@ -840,7 +841,7 @@ func (repo *Repository) TemplateRepo(ctx context.Context) *Repository {
type CountRepositoryOptions struct {
OwnerID int64
- Private util.OptionalBool
+ Private optional.Option[bool]
}
// CountRepositories returns number of repositories.
@@ -852,8 +853,8 @@ func CountRepositories(ctx context.Context, opts CountRepositoryOptions) (int64,
if opts.OwnerID > 0 {
sess.And("owner_id = ?", opts.OwnerID)
}
- if !opts.Private.IsNone() {
- sess.And("is_private=?", opts.Private.IsTrue())
+ if opts.Private.Has() {
+ sess.And("is_private=?", opts.Private.Value())
}
count, err := sess.Count(new(Repository))
diff --git a/models/repo/repo_test.go b/models/repo/repo_test.go
index ca9209d75153d..1a870224bf5d1 100644
--- a/models/repo/repo_test.go
+++ b/models/repo/repo_test.go
@@ -12,17 +12,17 @@ import (
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/markup"
+ "code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/test"
- "code.gitea.io/gitea/modules/util"
"github.com/stretchr/testify/assert"
)
var (
countRepospts = repo_model.CountRepositoryOptions{OwnerID: 10}
- countReposptsPublic = repo_model.CountRepositoryOptions{OwnerID: 10, Private: util.OptionalBoolFalse}
- countReposptsPrivate = repo_model.CountRepositoryOptions{OwnerID: 10, Private: util.OptionalBoolTrue}
+ countReposptsPublic = repo_model.CountRepositoryOptions{OwnerID: 10, Private: optional.Some(false)}
+ countReposptsPrivate = repo_model.CountRepositoryOptions{OwnerID: 10, Private: optional.Some(true)}
)
func TestGetRepositoryCount(t *testing.T) {
diff --git a/models/user/user.go b/models/user/user.go
index e92bbd4d0b09e..a898e71a2d710 100644
--- a/models/user/user.go
+++ b/models/user/user.go
@@ -715,7 +715,7 @@ func CreateUser(ctx context.Context, u *User, overwriteDefault ...*CreateUserOve
// IsLastAdminUser check whether user is the last admin
func IsLastAdminUser(ctx context.Context, user *User) bool {
- if user.IsAdmin && CountUsers(ctx, &CountUserFilter{IsAdmin: util.OptionalBoolTrue}) <= 1 {
+ if user.IsAdmin && CountUsers(ctx, &CountUserFilter{IsAdmin: optional.Some(true)}) <= 1 {
return true
}
return false
@@ -724,7 +724,7 @@ func IsLastAdminUser(ctx context.Context, user *User) bool {
// CountUserFilter represent optional filters for CountUsers
type CountUserFilter struct {
LastLoginSince *int64
- IsAdmin util.OptionalBool
+ IsAdmin optional.Option[bool]
}
// CountUsers returns number of users.
@@ -742,8 +742,8 @@ func countUsers(ctx context.Context, opts *CountUserFilter) int64 {
cond = cond.And(builder.Gte{"last_login_unix": *opts.LastLoginSince})
}
- if !opts.IsAdmin.IsNone() {
- cond = cond.And(builder.Eq{"is_admin": opts.IsAdmin.IsTrue()})
+ if opts.IsAdmin.Has() {
+ cond = cond.And(builder.Eq{"is_admin": opts.IsAdmin.Value()})
}
}
diff --git a/models/webhook/webhook.go b/models/webhook/webhook.go
index 4a84a3d411169..894357e36a12d 100644
--- a/models/webhook/webhook.go
+++ b/models/webhook/webhook.go
@@ -12,6 +12,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/secret"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
@@ -433,7 +434,7 @@ type ListWebhookOptions struct {
db.ListOptions
RepoID int64
OwnerID int64
- IsActive util.OptionalBool
+ IsActive optional.Option[bool]
}
func (opts ListWebhookOptions) ToConds() builder.Cond {
@@ -444,8 +445,8 @@ func (opts ListWebhookOptions) ToConds() builder.Cond {
if opts.OwnerID != 0 {
cond = cond.And(builder.Eq{"webhook.owner_id": opts.OwnerID})
}
- if !opts.IsActive.IsNone() {
- cond = cond.And(builder.Eq{"webhook.is_active": opts.IsActive.IsTrue()})
+ if opts.IsActive.Has() {
+ cond = cond.And(builder.Eq{"webhook.is_active": opts.IsActive.Value()})
}
return cond
}
diff --git a/models/webhook/webhook_system.go b/models/webhook/webhook_system.go
index 2e89f9547bba2..a2a9ee321ae92 100644
--- a/models/webhook/webhook_system.go
+++ b/models/webhook/webhook_system.go
@@ -8,7 +8,7 @@ import (
"fmt"
"code.gitea.io/gitea/models/db"
- "code.gitea.io/gitea/modules/util"
+ "code.gitea.io/gitea/modules/optional"
)
// GetDefaultWebhooks returns all admin-default webhooks.
@@ -34,15 +34,15 @@ func GetSystemOrDefaultWebhook(ctx context.Context, id int64) (*Webhook, error)
}
// GetSystemWebhooks returns all admin system webhooks.
-func GetSystemWebhooks(ctx context.Context, isActive util.OptionalBool) ([]*Webhook, error) {
+func GetSystemWebhooks(ctx context.Context, isActive optional.Option[bool]) ([]*Webhook, error) {
webhooks := make([]*Webhook, 0, 5)
- if isActive.IsNone() {
+ if !isActive.Has() {
return webhooks, db.GetEngine(ctx).
Where("repo_id=? AND owner_id=? AND is_system_webhook=?", 0, 0, true).
Find(&webhooks)
}
return webhooks, db.GetEngine(ctx).
- Where("repo_id=? AND owner_id=? AND is_system_webhook=? AND is_active = ?", 0, 0, true, isActive.IsTrue()).
+ Where("repo_id=? AND owner_id=? AND is_system_webhook=? AND is_active = ?", 0, 0, true, isActive.Value()).
Find(&webhooks)
}
diff --git a/models/webhook/webhook_test.go b/models/webhook/webhook_test.go
index 694fd7a873f37..c70c8e99fcc7d 100644
--- a/models/webhook/webhook_test.go
+++ b/models/webhook/webhook_test.go
@@ -11,9 +11,9 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/modules/json"
+ "code.gitea.io/gitea/modules/optional"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil"
- "code.gitea.io/gitea/modules/util"
webhook_module "code.gitea.io/gitea/modules/webhook"
"github.com/stretchr/testify/assert"
@@ -123,7 +123,7 @@ func TestGetWebhookByOwnerID(t *testing.T) {
func TestGetActiveWebhooksByRepoID(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- hooks, err := db.Find[Webhook](db.DefaultContext, ListWebhookOptions{RepoID: 1, IsActive: util.OptionalBoolTrue})
+ hooks, err := db.Find[Webhook](db.DefaultContext, ListWebhookOptions{RepoID: 1, IsActive: optional.Some(true)})
assert.NoError(t, err)
if assert.Len(t, hooks, 1) {
assert.Equal(t, int64(1), hooks[0].ID)
@@ -143,7 +143,7 @@ func TestGetWebhooksByRepoID(t *testing.T) {
func TestGetActiveWebhooksByOwnerID(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- hooks, err := db.Find[Webhook](db.DefaultContext, ListWebhookOptions{OwnerID: 3, IsActive: util.OptionalBoolTrue})
+ hooks, err := db.Find[Webhook](db.DefaultContext, ListWebhookOptions{OwnerID: 3, IsActive: optional.Some(true)})
assert.NoError(t, err)
if assert.Len(t, hooks, 1) {
assert.Equal(t, int64(3), hooks[0].ID)
diff --git a/modules/git/command.go b/modules/git/command.go
index 9305ef6f928e7..371109730a23e 100644
--- a/modules/git/command.go
+++ b/modules/git/command.go
@@ -12,6 +12,7 @@ import (
"io"
"os"
"os/exec"
+ "runtime"
"strings"
"time"
@@ -344,6 +345,17 @@ func (c *Command) Run(opts *RunOpts) error {
log.Debug("slow git.Command.Run: %s (%s)", c, elapsed)
}
+ // We need to check if the context is canceled by the program on Windows.
+ // This is because Windows does not have signal checking when terminating the process.
+ // It always returns exit code 1, unlike Linux, which has many exit codes for signals.
+ if runtime.GOOS == "windows" &&
+ err != nil &&
+ err.Error() == "" &&
+ cmd.ProcessState.ExitCode() == 1 &&
+ ctx.Err() == context.Canceled {
+ return ctx.Err()
+ }
+
if err != nil && ctx.Err() != context.DeadlineExceeded {
return err
}
diff --git a/modules/indexer/issues/bleve/bleve.go b/modules/indexer/issues/bleve/bleve.go
index 7c82cfbb792ef..6a5d65cb665d0 100644
--- a/modules/indexer/issues/bleve/bleve.go
+++ b/modules/indexer/issues/bleve/bleve.go
@@ -175,11 +175,11 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) (
queries = append(queries, bleve.NewDisjunctionQuery(repoQueries...))
}
- if !options.IsPull.IsNone() {
- queries = append(queries, inner_bleve.BoolFieldQuery(options.IsPull.IsTrue(), "is_pull"))
+ if options.IsPull.Has() {
+ queries = append(queries, inner_bleve.BoolFieldQuery(options.IsPull.Value(), "is_pull"))
}
- if !options.IsClosed.IsNone() {
- queries = append(queries, inner_bleve.BoolFieldQuery(options.IsClosed.IsTrue(), "is_closed"))
+ if options.IsClosed.Has() {
+ queries = append(queries, inner_bleve.BoolFieldQuery(options.IsClosed.Value(), "is_closed"))
}
if options.NoLabelOnly {
diff --git a/modules/indexer/issues/db/options.go b/modules/indexer/issues/db/options.go
index 5406715bbcfb2..69146573a8682 100644
--- a/modules/indexer/issues/db/options.go
+++ b/modules/indexer/issues/db/options.go
@@ -11,6 +11,7 @@ import (
issue_model "code.gitea.io/gitea/models/issues"
"code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/indexer/issues/internal"
+ "code.gitea.io/gitea/modules/optional"
)
func ToDBOptions(ctx context.Context, options *internal.SearchOptions) (*issue_model.IssuesOptions, error) {
@@ -75,7 +76,7 @@ func ToDBOptions(ctx context.Context, options *internal.SearchOptions) (*issue_m
UpdatedAfterUnix: convertInt64(options.UpdatedAfterUnix),
UpdatedBeforeUnix: convertInt64(options.UpdatedBeforeUnix),
PriorityRepoID: 0,
- IsArchived: 0,
+ IsArchived: optional.None[bool](),
Org: nil,
Team: nil,
User: nil,
diff --git a/modules/indexer/issues/elasticsearch/elasticsearch.go b/modules/indexer/issues/elasticsearch/elasticsearch.go
index d059f76b3288a..3acd3ade71528 100644
--- a/modules/indexer/issues/elasticsearch/elasticsearch.go
+++ b/modules/indexer/issues/elasticsearch/elasticsearch.go
@@ -153,11 +153,11 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) (
query.Must(q)
}
- if !options.IsPull.IsNone() {
- query.Must(elastic.NewTermQuery("is_pull", options.IsPull.IsTrue()))
+ if options.IsPull.Has() {
+ query.Must(elastic.NewTermQuery("is_pull", options.IsPull.Value()))
}
- if !options.IsClosed.IsNone() {
- query.Must(elastic.NewTermQuery("is_closed", options.IsClosed.IsTrue()))
+ if options.IsClosed.Has() {
+ query.Must(elastic.NewTermQuery("is_closed", options.IsClosed.Value()))
}
if options.NoLabelOnly {
diff --git a/modules/indexer/issues/indexer_test.go b/modules/indexer/issues/indexer_test.go
index 3b96686d98ef0..10ffa7cbe6b63 100644
--- a/modules/indexer/issues/indexer_test.go
+++ b/modules/indexer/issues/indexer_test.go
@@ -10,8 +10,8 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/modules/indexer/issues/internal"
+ "code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/modules/util"
_ "code.gitea.io/gitea/models"
_ "code.gitea.io/gitea/models/actions"
@@ -210,13 +210,13 @@ func searchIssueIsPull(t *testing.T) {
}{
{
SearchOptions{
- IsPull: util.OptionalBoolFalse,
+ IsPull: optional.Some(false),
},
[]int64{17, 16, 15, 14, 13, 6, 5, 18, 10, 7, 4, 1},
},
{
SearchOptions{
- IsPull: util.OptionalBoolTrue,
+ IsPull: optional.Some(true),
},
[]int64{22, 21, 12, 11, 20, 19, 9, 8, 3, 2},
},
@@ -237,13 +237,13 @@ func searchIssueIsClosed(t *testing.T) {
}{
{
SearchOptions{
- IsClosed: util.OptionalBoolFalse,
+ IsClosed: optional.Some(false),
},
[]int64{22, 21, 17, 16, 15, 14, 13, 12, 11, 20, 6, 19, 18, 10, 7, 9, 8, 3, 2, 1},
},
{
SearchOptions{
- IsClosed: util.OptionalBoolTrue,
+ IsClosed: optional.Some(true),
},
[]int64{5, 4},
},
diff --git a/modules/indexer/issues/internal/model.go b/modules/indexer/issues/internal/model.go
index 031745dd2fcc1..947335d8ce9cb 100644
--- a/modules/indexer/issues/internal/model.go
+++ b/modules/indexer/issues/internal/model.go
@@ -5,8 +5,8 @@ package internal
import (
"code.gitea.io/gitea/models/db"
+ "code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/timeutil"
- "code.gitea.io/gitea/modules/util"
)
// IndexerData data stored in the issue indexer
@@ -77,8 +77,8 @@ type SearchOptions struct {
RepoIDs []int64 // repository IDs which the issues belong to
AllPublic bool // if include all public repositories
- IsPull util.OptionalBool // if the issues is a pull request
- IsClosed util.OptionalBool // if the issues is closed
+ IsPull optional.Option[bool] // if the issues is a pull request
+ IsClosed optional.Option[bool] // if the issues is closed
IncludedLabelIDs []int64 // labels the issues have
ExcludedLabelIDs []int64 // labels the issues don't have
diff --git a/modules/indexer/issues/internal/tests/tests.go b/modules/indexer/issues/internal/tests/tests.go
index 06fddeb65b627..67244715394dd 100644
--- a/modules/indexer/issues/internal/tests/tests.go
+++ b/modules/indexer/issues/internal/tests/tests.go
@@ -16,8 +16,8 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/indexer/issues/internal"
+ "code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/timeutil"
- "code.gitea.io/gitea/modules/util"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -166,7 +166,7 @@ var cases = []*testIndexerCase{
Paginator: &db.ListOptions{
PageSize: 5,
},
- IsPull: util.OptionalBoolFalse,
+ IsPull: optional.Some(false),
},
Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
assert.Equal(t, 5, len(result.Hits))
@@ -182,7 +182,7 @@ var cases = []*testIndexerCase{
Paginator: &db.ListOptions{
PageSize: 5,
},
- IsPull: util.OptionalBoolTrue,
+ IsPull: optional.Some(true),
},
Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
assert.Equal(t, 5, len(result.Hits))
@@ -198,7 +198,7 @@ var cases = []*testIndexerCase{
Paginator: &db.ListOptions{
PageSize: 5,
},
- IsClosed: util.OptionalBoolFalse,
+ IsClosed: optional.Some(false),
},
Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
assert.Equal(t, 5, len(result.Hits))
@@ -214,7 +214,7 @@ var cases = []*testIndexerCase{
Paginator: &db.ListOptions{
PageSize: 5,
},
- IsClosed: util.OptionalBoolTrue,
+ IsClosed: optional.Some(true),
},
Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
assert.Equal(t, 5, len(result.Hits))
diff --git a/modules/indexer/issues/meilisearch/meilisearch.go b/modules/indexer/issues/meilisearch/meilisearch.go
index ab8dcd0af45a8..325883196bb27 100644
--- a/modules/indexer/issues/meilisearch/meilisearch.go
+++ b/modules/indexer/issues/meilisearch/meilisearch.go
@@ -131,11 +131,11 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) (
query.And(q)
}
- if !options.IsPull.IsNone() {
- query.And(inner_meilisearch.NewFilterEq("is_pull", options.IsPull.IsTrue()))
+ if options.IsPull.Has() {
+ query.And(inner_meilisearch.NewFilterEq("is_pull", options.IsPull.Value()))
}
- if !options.IsClosed.IsNone() {
- query.And(inner_meilisearch.NewFilterEq("is_closed", options.IsClosed.IsTrue()))
+ if options.IsClosed.Has() {
+ query.And(inner_meilisearch.NewFilterEq("is_closed", options.IsClosed.Value()))
}
if options.NoLabelOnly {
diff --git a/modules/queue/workergroup.go b/modules/queue/workergroup.go
index 147a4f335e101..e3801ef2b2dd0 100644
--- a/modules/queue/workergroup.go
+++ b/modules/queue/workergroup.go
@@ -60,6 +60,9 @@ func (q *WorkerPoolQueue[T]) doDispatchBatchToWorker(wg *workerGroup[T], flushCh
full = true
}
+ // TODO: the logic could be improved in the future, to avoid a data-race between "doStartNewWorker" and "workerNum"
+ // The root problem is that if we skip "doStartNewWorker" here, the "workerNum" might be decreased by other workers later
+ // So ideally, it should check whether there are enough workers by some approaches, and start new workers if necessary.
q.workerNumMu.Lock()
noWorker := q.workerNum == 0
if full || noWorker {
@@ -143,7 +146,11 @@ func (q *WorkerPoolQueue[T]) doStartNewWorker(wp *workerGroup[T]) {
log.Debug("Queue %q starts new worker", q.GetName())
defer log.Debug("Queue %q stops idle worker", q.GetName())
+ atomic.AddInt32(&q.workerStartedCounter, 1) // Only increase counter, used for debugging
+
t := time.NewTicker(workerIdleDuration)
+ defer t.Stop()
+
keepWorking := true
stopWorking := func() {
q.workerNumMu.Lock()
@@ -158,13 +165,18 @@ func (q *WorkerPoolQueue[T]) doStartNewWorker(wp *workerGroup[T]) {
case batch, ok := <-q.batchChan:
if !ok {
stopWorking()
- } else {
- q.doWorkerHandle(batch)
- t.Reset(workerIdleDuration)
+ continue
+ }
+ q.doWorkerHandle(batch)
+ // reset the idle ticker, and drain the tick after reset in case a tick is already triggered
+ t.Reset(workerIdleDuration)
+ select {
+ case <-t.C:
+ default:
}
case <-t.C:
q.workerNumMu.Lock()
- keepWorking = q.workerNum <= 1
+ keepWorking = q.workerNum <= 1 // keep the last worker running
if !keepWorking {
q.workerNum--
}
diff --git a/modules/queue/workerqueue.go b/modules/queue/workerqueue.go
index b28fd880270ab..4160622d81388 100644
--- a/modules/queue/workerqueue.go
+++ b/modules/queue/workerqueue.go
@@ -40,6 +40,8 @@ type WorkerPoolQueue[T any] struct {
workerMaxNum int
workerActiveNum int
workerNumMu sync.Mutex
+
+ workerStartedCounter int32
}
type flushType chan struct{}
diff --git a/modules/queue/workerqueue_test.go b/modules/queue/workerqueue_test.go
index e60120162a706..e09669c54255e 100644
--- a/modules/queue/workerqueue_test.go
+++ b/modules/queue/workerqueue_test.go
@@ -11,6 +11,7 @@ import (
"time"
"code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/test"
"github.com/stretchr/testify/assert"
)
@@ -175,11 +176,7 @@ func testWorkerPoolQueuePersistence(t *testing.T, queueSetting setting.QueueSett
}
func TestWorkerPoolQueueActiveWorkers(t *testing.T) {
- oldWorkerIdleDuration := workerIdleDuration
- workerIdleDuration = 300 * time.Millisecond
- defer func() {
- workerIdleDuration = oldWorkerIdleDuration
- }()
+ defer test.MockVariableValue(&workerIdleDuration, 300*time.Millisecond)()
handler := func(items ...int) (unhandled []int) {
time.Sleep(100 * time.Millisecond)
@@ -250,3 +247,25 @@ func TestWorkerPoolQueueShutdown(t *testing.T) {
q, _ = newWorkerPoolQueueForTest("test-workpoolqueue", qs, handler, false)
assert.EqualValues(t, 20, q.GetQueueItemNumber())
}
+
+func TestWorkerPoolQueueWorkerIdleReset(t *testing.T) {
+ defer test.MockVariableValue(&workerIdleDuration, 10*time.Millisecond)()
+
+ handler := func(items ...int) (unhandled []int) {
+ time.Sleep(50 * time.Millisecond)
+ return nil
+ }
+
+ q, _ := newWorkerPoolQueueForTest("test-workpoolqueue", setting.QueueSettings{Type: "channel", BatchLength: 1, MaxWorkers: 2, Length: 100}, handler, false)
+ stop := runWorkerPoolQueue(q)
+ for i := 0; i < 20; i++ {
+ assert.NoError(t, q.Push(i))
+ }
+
+ time.Sleep(500 * time.Millisecond)
+ assert.EqualValues(t, 2, q.GetWorkerNumber())
+ assert.EqualValues(t, 2, q.GetWorkerActiveNumber())
+ // when the queue never becomes empty, the existing workers should keep working
+ assert.EqualValues(t, 2, q.workerStartedCounter)
+ stop()
+}
diff --git a/modules/references/references.go b/modules/references/references.go
index 7758312564508..761d6ee3d1843 100644
--- a/modules/references/references.go
+++ b/modules/references/references.go
@@ -31,9 +31,9 @@ var (
// mentionPattern matches all mentions in the form of "@user" or "@org/team"
mentionPattern = regexp.MustCompile(`(?:\s|^|\(|\[)(@[0-9a-zA-Z-_]+|@[0-9a-zA-Z-_]+\/?[0-9a-zA-Z-_]+|@[0-9a-zA-Z-_][0-9a-zA-Z-_.]+\/?[0-9a-zA-Z-_.]+[0-9a-zA-Z-_])(?:\s|[:,;.?!]\s|[:,;.?!]?$|\)|\])`)
// issueNumericPattern matches string that references to a numeric issue, e.g. #1287
- issueNumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[|\')([#!][0-9]+)(?:\s|$|\)|\]|[:;,.?!]\s|[:;,.?!]$)`)
+ issueNumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[|\'|\")([#!][0-9]+)(?:\s|$|\)|\]|\'|\"|[:;,.?!]\s|[:;,.?!]$)`)
// issueAlphanumericPattern matches string that references to an alphanumeric issue, e.g. ABC-1234
- issueAlphanumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[)([A-Z]{1,10}-[1-9][0-9]*)(?:\s|$|\)|\]|:|\.(\s|$))`)
+ issueAlphanumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[|\"|\')([A-Z]{1,10}-[1-9][0-9]*)(?:\s|$|\)|\]|:|\.(\s|$)|\"|\')`)
// crossReferenceIssueNumericPattern matches string that references a numeric issue in a different repository
// e.g. org/repo#12345
crossReferenceIssueNumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[)([0-9a-zA-Z-_\.]+/[0-9a-zA-Z-_\.]+[#!][0-9]+)(?:\s|$|\)|\]|[:;,.?!]\s|[:;,.?!]$)`)
diff --git a/modules/references/references_test.go b/modules/references/references_test.go
index ba7dda80ccf9c..0c32933619107 100644
--- a/modules/references/references_test.go
+++ b/modules/references/references_test.go
@@ -429,6 +429,8 @@ func TestRegExp_issueNumericPattern(t *testing.T) {
" #12",
"#12:",
"ref: #12: msg",
+ "\"#1234\"",
+ "'#1234'",
}
falseTestCases := []string{
"# 1234",
@@ -459,6 +461,8 @@ func TestRegExp_issueAlphanumericPattern(t *testing.T) {
"(ABC-123)",
"[ABC-123]",
"ABC-123:",
+ "\"ABC-123\"",
+ "'ABC-123'",
}
falseTestCases := []string{
"RC-08",
diff --git a/modules/util/util.go b/modules/util/util.go
index 615f654e47523..5c751581965cb 100644
--- a/modules/util/util.go
+++ b/modules/util/util.go
@@ -17,57 +17,6 @@ import (
"golang.org/x/text/language"
)
-// OptionalBool a boolean that can be "null"
-type OptionalBool byte
-
-const (
- // OptionalBoolNone a "null" boolean value
- OptionalBoolNone OptionalBool = iota
- // OptionalBoolTrue a "true" boolean value
- OptionalBoolTrue
- // OptionalBoolFalse a "false" boolean value
- OptionalBoolFalse
-)
-
-// IsTrue return true if equal to OptionalBoolTrue
-func (o OptionalBool) IsTrue() bool {
- return o == OptionalBoolTrue
-}
-
-// IsFalse return true if equal to OptionalBoolFalse
-func (o OptionalBool) IsFalse() bool {
- return o == OptionalBoolFalse
-}
-
-// IsNone return true if equal to OptionalBoolNone
-func (o OptionalBool) IsNone() bool {
- return o == OptionalBoolNone
-}
-
-// ToGeneric converts OptionalBool to optional.Option[bool]
-func (o OptionalBool) ToGeneric() optional.Option[bool] {
- if o.IsNone() {
- return optional.None[bool]()
- }
- return optional.Some[bool](o.IsTrue())
-}
-
-// OptionalBoolFromGeneric converts optional.Option[bool] to OptionalBool
-func OptionalBoolFromGeneric(o optional.Option[bool]) OptionalBool {
- if o.Has() {
- return OptionalBoolOf(o.Value())
- }
- return OptionalBoolNone
-}
-
-// OptionalBoolOf get the corresponding OptionalBool of a bool
-func OptionalBoolOf(b bool) OptionalBool {
- if b {
- return OptionalBoolTrue
- }
- return OptionalBoolFalse
-}
-
// OptionalBoolParse get the corresponding optional.Option[bool] of a string using strconv.ParseBool
func OptionalBoolParse(s string) optional.Option[bool] {
v, e := strconv.ParseBool(s)
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index 6d4e109e1dc66..beda02603e3f9 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -1792,9 +1792,9 @@ pulls.unrelated_histories = Merge Failed: The merge head and base do not share a
pulls.merge_out_of_date = Merge Failed: Whilst generating the merge, the base was updated. Hint: Try again.
pulls.head_out_of_date = Merge Failed: Whilst generating the merge, the head was updated. Hint: Try again.
pulls.has_merged = Failed: The pull request has been merged, you cannot merge again or change the target branch.
-pulls.push_rejected = Merge Failed: The push was rejected. Review the Git Hooks for this repository.
+pulls.push_rejected = Push Failed: The push was rejected. Review the Git Hooks for this repository.
pulls.push_rejected_summary = Full Rejection Message
-pulls.push_rejected_no_message = Merge Failed: The push was rejected but there was no remote message.
Review the Git Hooks for this repository
+pulls.push_rejected_no_message = Push Failed: The push was rejected but there was no remote message. Review the Git Hooks for this repository
pulls.open_unmerged_pull_exists = `You cannot perform a reopen operation because there is a pending pull request (#%d) with identical properties.`
pulls.status_checking = Some checks are pending
pulls.status_checks_success = All checks were successful
diff --git a/routers/api/actions/artifact.pb.go b/routers/api/actions/artifact.pb.go
new file mode 100644
index 0000000000000..590eda9fb9a08
--- /dev/null
+++ b/routers/api/actions/artifact.pb.go
@@ -0,0 +1,1058 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.32.0
+// protoc v4.25.2
+// source: artifact.proto
+
+package actions
+
+import (
+ reflect "reflect"
+ sync "sync"
+
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ timestamppb "google.golang.org/protobuf/types/known/timestamppb"
+ wrapperspb "google.golang.org/protobuf/types/known/wrapperspb"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type CreateArtifactRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ WorkflowRunBackendId string `protobuf:"bytes,1,opt,name=workflow_run_backend_id,json=workflowRunBackendId,proto3" json:"workflow_run_backend_id,omitempty"`
+ WorkflowJobRunBackendId string `protobuf:"bytes,2,opt,name=workflow_job_run_backend_id,json=workflowJobRunBackendId,proto3" json:"workflow_job_run_backend_id,omitempty"`
+ Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"`
+ ExpiresAt *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=expires_at,json=expiresAt,proto3" json:"expires_at,omitempty"`
+ Version int32 `protobuf:"varint,5,opt,name=version,proto3" json:"version,omitempty"`
+}
+
+func (x *CreateArtifactRequest) Reset() {
+ *x = CreateArtifactRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_artifact_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *CreateArtifactRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CreateArtifactRequest) ProtoMessage() {}
+
+func (x *CreateArtifactRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_artifact_proto_msgTypes[0]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use CreateArtifactRequest.ProtoReflect.Descriptor instead.
+func (*CreateArtifactRequest) Descriptor() ([]byte, []int) {
+ return file_artifact_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *CreateArtifactRequest) GetWorkflowRunBackendId() string {
+ if x != nil {
+ return x.WorkflowRunBackendId
+ }
+ return ""
+}
+
+func (x *CreateArtifactRequest) GetWorkflowJobRunBackendId() string {
+ if x != nil {
+ return x.WorkflowJobRunBackendId
+ }
+ return ""
+}
+
+func (x *CreateArtifactRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *CreateArtifactRequest) GetExpiresAt() *timestamppb.Timestamp {
+ if x != nil {
+ return x.ExpiresAt
+ }
+ return nil
+}
+
+func (x *CreateArtifactRequest) GetVersion() int32 {
+ if x != nil {
+ return x.Version
+ }
+ return 0
+}
+
+type CreateArtifactResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Ok bool `protobuf:"varint,1,opt,name=ok,proto3" json:"ok,omitempty"`
+ SignedUploadUrl string `protobuf:"bytes,2,opt,name=signed_upload_url,json=signedUploadUrl,proto3" json:"signed_upload_url,omitempty"`
+}
+
+func (x *CreateArtifactResponse) Reset() {
+ *x = CreateArtifactResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_artifact_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *CreateArtifactResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CreateArtifactResponse) ProtoMessage() {}
+
+func (x *CreateArtifactResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_artifact_proto_msgTypes[1]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use CreateArtifactResponse.ProtoReflect.Descriptor instead.
+func (*CreateArtifactResponse) Descriptor() ([]byte, []int) {
+ return file_artifact_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *CreateArtifactResponse) GetOk() bool {
+ if x != nil {
+ return x.Ok
+ }
+ return false
+}
+
+func (x *CreateArtifactResponse) GetSignedUploadUrl() string {
+ if x != nil {
+ return x.SignedUploadUrl
+ }
+ return ""
+}
+
+type FinalizeArtifactRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ WorkflowRunBackendId string `protobuf:"bytes,1,opt,name=workflow_run_backend_id,json=workflowRunBackendId,proto3" json:"workflow_run_backend_id,omitempty"`
+ WorkflowJobRunBackendId string `protobuf:"bytes,2,opt,name=workflow_job_run_backend_id,json=workflowJobRunBackendId,proto3" json:"workflow_job_run_backend_id,omitempty"`
+ Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"`
+ Size int64 `protobuf:"varint,4,opt,name=size,proto3" json:"size,omitempty"`
+ Hash *wrapperspb.StringValue `protobuf:"bytes,5,opt,name=hash,proto3" json:"hash,omitempty"`
+}
+
+func (x *FinalizeArtifactRequest) Reset() {
+ *x = FinalizeArtifactRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_artifact_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *FinalizeArtifactRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*FinalizeArtifactRequest) ProtoMessage() {}
+
+func (x *FinalizeArtifactRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_artifact_proto_msgTypes[2]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use FinalizeArtifactRequest.ProtoReflect.Descriptor instead.
+func (*FinalizeArtifactRequest) Descriptor() ([]byte, []int) {
+ return file_artifact_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *FinalizeArtifactRequest) GetWorkflowRunBackendId() string {
+ if x != nil {
+ return x.WorkflowRunBackendId
+ }
+ return ""
+}
+
+func (x *FinalizeArtifactRequest) GetWorkflowJobRunBackendId() string {
+ if x != nil {
+ return x.WorkflowJobRunBackendId
+ }
+ return ""
+}
+
+func (x *FinalizeArtifactRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *FinalizeArtifactRequest) GetSize() int64 {
+ if x != nil {
+ return x.Size
+ }
+ return 0
+}
+
+func (x *FinalizeArtifactRequest) GetHash() *wrapperspb.StringValue {
+ if x != nil {
+ return x.Hash
+ }
+ return nil
+}
+
+type FinalizeArtifactResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Ok bool `protobuf:"varint,1,opt,name=ok,proto3" json:"ok,omitempty"`
+ ArtifactId int64 `protobuf:"varint,2,opt,name=artifact_id,json=artifactId,proto3" json:"artifact_id,omitempty"`
+}
+
+func (x *FinalizeArtifactResponse) Reset() {
+ *x = FinalizeArtifactResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_artifact_proto_msgTypes[3]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *FinalizeArtifactResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*FinalizeArtifactResponse) ProtoMessage() {}
+
+func (x *FinalizeArtifactResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_artifact_proto_msgTypes[3]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use FinalizeArtifactResponse.ProtoReflect.Descriptor instead.
+func (*FinalizeArtifactResponse) Descriptor() ([]byte, []int) {
+ return file_artifact_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *FinalizeArtifactResponse) GetOk() bool {
+ if x != nil {
+ return x.Ok
+ }
+ return false
+}
+
+func (x *FinalizeArtifactResponse) GetArtifactId() int64 {
+ if x != nil {
+ return x.ArtifactId
+ }
+ return 0
+}
+
+type ListArtifactsRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ WorkflowRunBackendId string `protobuf:"bytes,1,opt,name=workflow_run_backend_id,json=workflowRunBackendId,proto3" json:"workflow_run_backend_id,omitempty"`
+ WorkflowJobRunBackendId string `protobuf:"bytes,2,opt,name=workflow_job_run_backend_id,json=workflowJobRunBackendId,proto3" json:"workflow_job_run_backend_id,omitempty"`
+ NameFilter *wrapperspb.StringValue `protobuf:"bytes,3,opt,name=name_filter,json=nameFilter,proto3" json:"name_filter,omitempty"`
+ IdFilter *wrapperspb.Int64Value `protobuf:"bytes,4,opt,name=id_filter,json=idFilter,proto3" json:"id_filter,omitempty"`
+}
+
+func (x *ListArtifactsRequest) Reset() {
+ *x = ListArtifactsRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_artifact_proto_msgTypes[4]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ListArtifactsRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ListArtifactsRequest) ProtoMessage() {}
+
+func (x *ListArtifactsRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_artifact_proto_msgTypes[4]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ListArtifactsRequest.ProtoReflect.Descriptor instead.
+func (*ListArtifactsRequest) Descriptor() ([]byte, []int) {
+ return file_artifact_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *ListArtifactsRequest) GetWorkflowRunBackendId() string {
+ if x != nil {
+ return x.WorkflowRunBackendId
+ }
+ return ""
+}
+
+func (x *ListArtifactsRequest) GetWorkflowJobRunBackendId() string {
+ if x != nil {
+ return x.WorkflowJobRunBackendId
+ }
+ return ""
+}
+
+func (x *ListArtifactsRequest) GetNameFilter() *wrapperspb.StringValue {
+ if x != nil {
+ return x.NameFilter
+ }
+ return nil
+}
+
+func (x *ListArtifactsRequest) GetIdFilter() *wrapperspb.Int64Value {
+ if x != nil {
+ return x.IdFilter
+ }
+ return nil
+}
+
+type ListArtifactsResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Artifacts []*ListArtifactsResponse_MonolithArtifact `protobuf:"bytes,1,rep,name=artifacts,proto3" json:"artifacts,omitempty"`
+}
+
+func (x *ListArtifactsResponse) Reset() {
+ *x = ListArtifactsResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_artifact_proto_msgTypes[5]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ListArtifactsResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ListArtifactsResponse) ProtoMessage() {}
+
+func (x *ListArtifactsResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_artifact_proto_msgTypes[5]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ListArtifactsResponse.ProtoReflect.Descriptor instead.
+func (*ListArtifactsResponse) Descriptor() ([]byte, []int) {
+ return file_artifact_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *ListArtifactsResponse) GetArtifacts() []*ListArtifactsResponse_MonolithArtifact {
+ if x != nil {
+ return x.Artifacts
+ }
+ return nil
+}
+
+type ListArtifactsResponse_MonolithArtifact struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ WorkflowRunBackendId string `protobuf:"bytes,1,opt,name=workflow_run_backend_id,json=workflowRunBackendId,proto3" json:"workflow_run_backend_id,omitempty"`
+ WorkflowJobRunBackendId string `protobuf:"bytes,2,opt,name=workflow_job_run_backend_id,json=workflowJobRunBackendId,proto3" json:"workflow_job_run_backend_id,omitempty"`
+ DatabaseId int64 `protobuf:"varint,3,opt,name=database_id,json=databaseId,proto3" json:"database_id,omitempty"`
+ Name string `protobuf:"bytes,4,opt,name=name,proto3" json:"name,omitempty"`
+ Size int64 `protobuf:"varint,5,opt,name=size,proto3" json:"size,omitempty"`
+ CreatedAt *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"`
+}
+
+func (x *ListArtifactsResponse_MonolithArtifact) Reset() {
+ *x = ListArtifactsResponse_MonolithArtifact{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_artifact_proto_msgTypes[6]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ListArtifactsResponse_MonolithArtifact) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ListArtifactsResponse_MonolithArtifact) ProtoMessage() {}
+
+func (x *ListArtifactsResponse_MonolithArtifact) ProtoReflect() protoreflect.Message {
+ mi := &file_artifact_proto_msgTypes[6]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ListArtifactsResponse_MonolithArtifact.ProtoReflect.Descriptor instead.
+func (*ListArtifactsResponse_MonolithArtifact) Descriptor() ([]byte, []int) {
+ return file_artifact_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *ListArtifactsResponse_MonolithArtifact) GetWorkflowRunBackendId() string {
+ if x != nil {
+ return x.WorkflowRunBackendId
+ }
+ return ""
+}
+
+func (x *ListArtifactsResponse_MonolithArtifact) GetWorkflowJobRunBackendId() string {
+ if x != nil {
+ return x.WorkflowJobRunBackendId
+ }
+ return ""
+}
+
+func (x *ListArtifactsResponse_MonolithArtifact) GetDatabaseId() int64 {
+ if x != nil {
+ return x.DatabaseId
+ }
+ return 0
+}
+
+func (x *ListArtifactsResponse_MonolithArtifact) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *ListArtifactsResponse_MonolithArtifact) GetSize() int64 {
+ if x != nil {
+ return x.Size
+ }
+ return 0
+}
+
+func (x *ListArtifactsResponse_MonolithArtifact) GetCreatedAt() *timestamppb.Timestamp {
+ if x != nil {
+ return x.CreatedAt
+ }
+ return nil
+}
+
+type GetSignedArtifactURLRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ WorkflowRunBackendId string `protobuf:"bytes,1,opt,name=workflow_run_backend_id,json=workflowRunBackendId,proto3" json:"workflow_run_backend_id,omitempty"`
+ WorkflowJobRunBackendId string `protobuf:"bytes,2,opt,name=workflow_job_run_backend_id,json=workflowJobRunBackendId,proto3" json:"workflow_job_run_backend_id,omitempty"`
+ Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"`
+}
+
+func (x *GetSignedArtifactURLRequest) Reset() {
+ *x = GetSignedArtifactURLRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_artifact_proto_msgTypes[7]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *GetSignedArtifactURLRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetSignedArtifactURLRequest) ProtoMessage() {}
+
+func (x *GetSignedArtifactURLRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_artifact_proto_msgTypes[7]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetSignedArtifactURLRequest.ProtoReflect.Descriptor instead.
+func (*GetSignedArtifactURLRequest) Descriptor() ([]byte, []int) {
+ return file_artifact_proto_rawDescGZIP(), []int{7}
+}
+
+func (x *GetSignedArtifactURLRequest) GetWorkflowRunBackendId() string {
+ if x != nil {
+ return x.WorkflowRunBackendId
+ }
+ return ""
+}
+
+func (x *GetSignedArtifactURLRequest) GetWorkflowJobRunBackendId() string {
+ if x != nil {
+ return x.WorkflowJobRunBackendId
+ }
+ return ""
+}
+
+func (x *GetSignedArtifactURLRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+type GetSignedArtifactURLResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ SignedUrl string `protobuf:"bytes,1,opt,name=signed_url,json=signedUrl,proto3" json:"signed_url,omitempty"`
+}
+
+func (x *GetSignedArtifactURLResponse) Reset() {
+ *x = GetSignedArtifactURLResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_artifact_proto_msgTypes[8]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *GetSignedArtifactURLResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetSignedArtifactURLResponse) ProtoMessage() {}
+
+func (x *GetSignedArtifactURLResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_artifact_proto_msgTypes[8]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetSignedArtifactURLResponse.ProtoReflect.Descriptor instead.
+func (*GetSignedArtifactURLResponse) Descriptor() ([]byte, []int) {
+ return file_artifact_proto_rawDescGZIP(), []int{8}
+}
+
+func (x *GetSignedArtifactURLResponse) GetSignedUrl() string {
+ if x != nil {
+ return x.SignedUrl
+ }
+ return ""
+}
+
+type DeleteArtifactRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ WorkflowRunBackendId string `protobuf:"bytes,1,opt,name=workflow_run_backend_id,json=workflowRunBackendId,proto3" json:"workflow_run_backend_id,omitempty"`
+ WorkflowJobRunBackendId string `protobuf:"bytes,2,opt,name=workflow_job_run_backend_id,json=workflowJobRunBackendId,proto3" json:"workflow_job_run_backend_id,omitempty"`
+ Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"`
+}
+
+func (x *DeleteArtifactRequest) Reset() {
+ *x = DeleteArtifactRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_artifact_proto_msgTypes[9]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *DeleteArtifactRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DeleteArtifactRequest) ProtoMessage() {}
+
+func (x *DeleteArtifactRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_artifact_proto_msgTypes[9]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use DeleteArtifactRequest.ProtoReflect.Descriptor instead.
+func (*DeleteArtifactRequest) Descriptor() ([]byte, []int) {
+ return file_artifact_proto_rawDescGZIP(), []int{9}
+}
+
+func (x *DeleteArtifactRequest) GetWorkflowRunBackendId() string {
+ if x != nil {
+ return x.WorkflowRunBackendId
+ }
+ return ""
+}
+
+func (x *DeleteArtifactRequest) GetWorkflowJobRunBackendId() string {
+ if x != nil {
+ return x.WorkflowJobRunBackendId
+ }
+ return ""
+}
+
+func (x *DeleteArtifactRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+type DeleteArtifactResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Ok bool `protobuf:"varint,1,opt,name=ok,proto3" json:"ok,omitempty"`
+ ArtifactId int64 `protobuf:"varint,2,opt,name=artifact_id,json=artifactId,proto3" json:"artifact_id,omitempty"`
+}
+
+func (x *DeleteArtifactResponse) Reset() {
+ *x = DeleteArtifactResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_artifact_proto_msgTypes[10]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *DeleteArtifactResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DeleteArtifactResponse) ProtoMessage() {}
+
+func (x *DeleteArtifactResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_artifact_proto_msgTypes[10]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use DeleteArtifactResponse.ProtoReflect.Descriptor instead.
+func (*DeleteArtifactResponse) Descriptor() ([]byte, []int) {
+ return file_artifact_proto_rawDescGZIP(), []int{10}
+}
+
+func (x *DeleteArtifactResponse) GetOk() bool {
+ if x != nil {
+ return x.Ok
+ }
+ return false
+}
+
+func (x *DeleteArtifactResponse) GetArtifactId() int64 {
+ if x != nil {
+ return x.ArtifactId
+ }
+ return 0
+}
+
+var File_artifact_proto protoreflect.FileDescriptor
+
+var file_artifact_proto_rawDesc = []byte{
+ 0x0a, 0x0e, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x12, 0x1d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+ 0x2e, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x1a,
+ 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
+ 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
+ 0x66, 0x2f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x22, 0xf5, 0x01, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x72, 0x74, 0x69, 0x66,
+ 0x61, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x35, 0x0a, 0x17, 0x77, 0x6f,
+ 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x72, 0x75, 0x6e, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x65,
+ 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x77, 0x6f, 0x72,
+ 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49,
+ 0x64, 0x12, 0x3c, 0x0a, 0x1b, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x6a, 0x6f,
+ 0x62, 0x5f, 0x72, 0x75, 0x6e, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x5f, 0x69, 0x64,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x17, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77,
+ 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x64, 0x12,
+ 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e,
+ 0x61, 0x6d, 0x65, 0x12, 0x39, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x61,
+ 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74,
+ 0x61, 0x6d, 0x70, 0x52, 0x09, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x12, 0x18,
+ 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52,
+ 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x54, 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61,
+ 0x74, 0x65, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+ 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x6f, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x02,
+ 0x6f, 0x6b, 0x12, 0x2a, 0x0a, 0x11, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x75, 0x70, 0x6c,
+ 0x6f, 0x61, 0x64, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73,
+ 0x69, 0x67, 0x6e, 0x65, 0x64, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x55, 0x72, 0x6c, 0x22, 0xe8,
+ 0x01, 0x0a, 0x17, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x41, 0x72, 0x74, 0x69, 0x66,
+ 0x61, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x35, 0x0a, 0x17, 0x77, 0x6f,
+ 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x72, 0x75, 0x6e, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x65,
+ 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x77, 0x6f, 0x72,
+ 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49,
+ 0x64, 0x12, 0x3c, 0x0a, 0x1b, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x6a, 0x6f,
+ 0x62, 0x5f, 0x72, 0x75, 0x6e, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x5f, 0x69, 0x64,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x17, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77,
+ 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x64, 0x12,
+ 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e,
+ 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28,
+ 0x03, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x30, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18,
+ 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61,
+ 0x6c, 0x75, 0x65, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x22, 0x4b, 0x0a, 0x18, 0x46, 0x69, 0x6e,
+ 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, 0x65, 0x73,
+ 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x6f, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28,
+ 0x08, 0x52, 0x02, 0x6f, 0x6b, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63,
+ 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x61, 0x72, 0x74, 0x69,
+ 0x66, 0x61, 0x63, 0x74, 0x49, 0x64, 0x22, 0x84, 0x02, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x41,
+ 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
+ 0x35, 0x0a, 0x17, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x72, 0x75, 0x6e, 0x5f,
+ 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x14, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x42, 0x61, 0x63,
+ 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x64, 0x12, 0x3c, 0x0a, 0x1b, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c,
+ 0x6f, 0x77, 0x5f, 0x6a, 0x6f, 0x62, 0x5f, 0x72, 0x75, 0x6e, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x65,
+ 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x17, 0x77, 0x6f, 0x72,
+ 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x65,
+ 0x6e, 0x64, 0x49, 0x64, 0x12, 0x3d, 0x0a, 0x0b, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x66, 0x69, 0x6c,
+ 0x74, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69,
+ 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, 0x6e, 0x61, 0x6d, 0x65, 0x46, 0x69, 0x6c,
+ 0x74, 0x65, 0x72, 0x12, 0x38, 0x0a, 0x09, 0x69, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72,
+ 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61,
+ 0x6c, 0x75, 0x65, 0x52, 0x08, 0x69, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x7c, 0x0a,
+ 0x15, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x52, 0x65,
+ 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x09, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61,
+ 0x63, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x67, 0x69, 0x74, 0x68,
+ 0x75, 0x62, 0x2e, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x72, 0x65, 0x73, 0x75, 0x6c,
+ 0x74, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x72,
+ 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f,
+ 0x4d, 0x6f, 0x6e, 0x6f, 0x6c, 0x69, 0x74, 0x68, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74,
+ 0x52, 0x09, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x22, 0xa1, 0x02, 0x0a, 0x26,
+ 0x4c, 0x69, 0x73, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73,
+ 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x6f, 0x6c, 0x69, 0x74, 0x68, 0x41, 0x72,
+ 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x12, 0x35, 0x0a, 0x17, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c,
+ 0x6f, 0x77, 0x5f, 0x72, 0x75, 0x6e, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x5f, 0x69,
+ 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f,
+ 0x77, 0x52, 0x75, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x64, 0x12, 0x3c, 0x0a,
+ 0x1b, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x6a, 0x6f, 0x62, 0x5f, 0x72, 0x75,
+ 0x6e, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x17, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x4a, 0x6f, 0x62, 0x52,
+ 0x75, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x64,
+ 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03,
+ 0x52, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04,
+ 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
+ 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04,
+ 0x73, 0x69, 0x7a, 0x65, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f,
+ 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73,
+ 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22,
+ 0xa6, 0x01, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x41, 0x72, 0x74,
+ 0x69, 0x66, 0x61, 0x63, 0x74, 0x55, 0x52, 0x4c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
+ 0x35, 0x0a, 0x17, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x72, 0x75, 0x6e, 0x5f,
+ 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x14, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x42, 0x61, 0x63,
+ 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x64, 0x12, 0x3c, 0x0a, 0x1b, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c,
+ 0x6f, 0x77, 0x5f, 0x6a, 0x6f, 0x62, 0x5f, 0x72, 0x75, 0x6e, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x65,
+ 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x17, 0x77, 0x6f, 0x72,
+ 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x65,
+ 0x6e, 0x64, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3d, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x53,
+ 0x69, 0x67, 0x6e, 0x65, 0x64, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x55, 0x52, 0x4c,
+ 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x69, 0x67, 0x6e,
+ 0x65, 0x64, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x69,
+ 0x67, 0x6e, 0x65, 0x64, 0x55, 0x72, 0x6c, 0x22, 0xa0, 0x01, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65,
+ 0x74, 0x65, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+ 0x74, 0x12, 0x35, 0x0a, 0x17, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x72, 0x75,
+ 0x6e, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x14, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x42,
+ 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x64, 0x12, 0x3c, 0x0a, 0x1b, 0x77, 0x6f, 0x72, 0x6b,
+ 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x6a, 0x6f, 0x62, 0x5f, 0x72, 0x75, 0x6e, 0x5f, 0x62, 0x61, 0x63,
+ 0x6b, 0x65, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x17, 0x77,
+ 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x4a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x42, 0x61, 0x63,
+ 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x49, 0x0a, 0x16, 0x44, 0x65,
+ 0x6c, 0x65, 0x74, 0x65, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70,
+ 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x6f, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08,
+ 0x52, 0x02, 0x6f, 0x6b, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74,
+ 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x61, 0x72, 0x74, 0x69, 0x66,
+ 0x61, 0x63, 0x74, 0x49, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+ file_artifact_proto_rawDescOnce sync.Once
+ file_artifact_proto_rawDescData = file_artifact_proto_rawDesc
+)
+
+func file_artifact_proto_rawDescGZIP() []byte {
+ file_artifact_proto_rawDescOnce.Do(func() {
+ file_artifact_proto_rawDescData = protoimpl.X.CompressGZIP(file_artifact_proto_rawDescData)
+ })
+ return file_artifact_proto_rawDescData
+}
+
+var (
+ file_artifact_proto_msgTypes = make([]protoimpl.MessageInfo, 11)
+ file_artifact_proto_goTypes = []interface{}{
+ (*CreateArtifactRequest)(nil), // 0: github.actions.results.api.v1.CreateArtifactRequest
+ (*CreateArtifactResponse)(nil), // 1: github.actions.results.api.v1.CreateArtifactResponse
+ (*FinalizeArtifactRequest)(nil), // 2: github.actions.results.api.v1.FinalizeArtifactRequest
+ (*FinalizeArtifactResponse)(nil), // 3: github.actions.results.api.v1.FinalizeArtifactResponse
+ (*ListArtifactsRequest)(nil), // 4: github.actions.results.api.v1.ListArtifactsRequest
+ (*ListArtifactsResponse)(nil), // 5: github.actions.results.api.v1.ListArtifactsResponse
+ (*ListArtifactsResponse_MonolithArtifact)(nil), // 6: github.actions.results.api.v1.ListArtifactsResponse_MonolithArtifact
+ (*GetSignedArtifactURLRequest)(nil), // 7: github.actions.results.api.v1.GetSignedArtifactURLRequest
+ (*GetSignedArtifactURLResponse)(nil), // 8: github.actions.results.api.v1.GetSignedArtifactURLResponse
+ (*DeleteArtifactRequest)(nil), // 9: github.actions.results.api.v1.DeleteArtifactRequest
+ (*DeleteArtifactResponse)(nil), // 10: github.actions.results.api.v1.DeleteArtifactResponse
+ (*timestamppb.Timestamp)(nil), // 11: google.protobuf.Timestamp
+ (*wrapperspb.StringValue)(nil), // 12: google.protobuf.StringValue
+ (*wrapperspb.Int64Value)(nil), // 13: google.protobuf.Int64Value
+ }
+)
+
+var file_artifact_proto_depIdxs = []int32{
+ 11, // 0: github.actions.results.api.v1.CreateArtifactRequest.expires_at:type_name -> google.protobuf.Timestamp
+ 12, // 1: github.actions.results.api.v1.FinalizeArtifactRequest.hash:type_name -> google.protobuf.StringValue
+ 12, // 2: github.actions.results.api.v1.ListArtifactsRequest.name_filter:type_name -> google.protobuf.StringValue
+ 13, // 3: github.actions.results.api.v1.ListArtifactsRequest.id_filter:type_name -> google.protobuf.Int64Value
+ 6, // 4: github.actions.results.api.v1.ListArtifactsResponse.artifacts:type_name -> github.actions.results.api.v1.ListArtifactsResponse_MonolithArtifact
+ 11, // 5: github.actions.results.api.v1.ListArtifactsResponse_MonolithArtifact.created_at:type_name -> google.protobuf.Timestamp
+ 6, // [6:6] is the sub-list for method output_type
+ 6, // [6:6] is the sub-list for method input_type
+ 6, // [6:6] is the sub-list for extension type_name
+ 6, // [6:6] is the sub-list for extension extendee
+ 0, // [0:6] is the sub-list for field type_name
+}
+
+func init() { file_artifact_proto_init() }
+func file_artifact_proto_init() {
+ if File_artifact_proto != nil {
+ return
+ }
+ if !protoimpl.UnsafeEnabled {
+ file_artifact_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*CreateArtifactRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_artifact_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*CreateArtifactResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_artifact_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*FinalizeArtifactRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_artifact_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*FinalizeArtifactResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_artifact_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*ListArtifactsRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_artifact_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*ListArtifactsResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_artifact_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*ListArtifactsResponse_MonolithArtifact); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_artifact_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*GetSignedArtifactURLRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_artifact_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*GetSignedArtifactURLResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_artifact_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*DeleteArtifactRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_artifact_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*DeleteArtifactResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_artifact_proto_rawDesc,
+ NumEnums: 0,
+ NumMessages: 11,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_artifact_proto_goTypes,
+ DependencyIndexes: file_artifact_proto_depIdxs,
+ MessageInfos: file_artifact_proto_msgTypes,
+ }.Build()
+ File_artifact_proto = out.File
+ file_artifact_proto_rawDesc = nil
+ file_artifact_proto_goTypes = nil
+ file_artifact_proto_depIdxs = nil
+}
diff --git a/routers/api/actions/artifact.proto b/routers/api/actions/artifact.proto
new file mode 100644
index 0000000000000..c68e5d030d09c
--- /dev/null
+++ b/routers/api/actions/artifact.proto
@@ -0,0 +1,73 @@
+syntax = "proto3";
+
+import "google/protobuf/timestamp.proto";
+import "google/protobuf/wrappers.proto";
+
+package github.actions.results.api.v1;
+
+message CreateArtifactRequest {
+ string workflow_run_backend_id = 1;
+ string workflow_job_run_backend_id = 2;
+ string name = 3;
+ google.protobuf.Timestamp expires_at = 4;
+ int32 version = 5;
+}
+
+message CreateArtifactResponse {
+ bool ok = 1;
+ string signed_upload_url = 2;
+}
+
+message FinalizeArtifactRequest {
+ string workflow_run_backend_id = 1;
+ string workflow_job_run_backend_id = 2;
+ string name = 3;
+ int64 size = 4;
+ google.protobuf.StringValue hash = 5;
+}
+
+message FinalizeArtifactResponse {
+ bool ok = 1;
+ int64 artifact_id = 2;
+}
+
+message ListArtifactsRequest {
+ string workflow_run_backend_id = 1;
+ string workflow_job_run_backend_id = 2;
+ google.protobuf.StringValue name_filter = 3;
+ google.protobuf.Int64Value id_filter = 4;
+}
+
+message ListArtifactsResponse {
+ repeated ListArtifactsResponse_MonolithArtifact artifacts = 1;
+}
+
+message ListArtifactsResponse_MonolithArtifact {
+ string workflow_run_backend_id = 1;
+ string workflow_job_run_backend_id = 2;
+ int64 database_id = 3;
+ string name = 4;
+ int64 size = 5;
+ google.protobuf.Timestamp created_at = 6;
+}
+
+message GetSignedArtifactURLRequest {
+ string workflow_run_backend_id = 1;
+ string workflow_job_run_backend_id = 2;
+ string name = 3;
+}
+
+message GetSignedArtifactURLResponse {
+ string signed_url = 1;
+}
+
+message DeleteArtifactRequest {
+ string workflow_run_backend_id = 1;
+ string workflow_job_run_backend_id = 2;
+ string name = 3;
+}
+
+message DeleteArtifactResponse {
+ bool ok = 1;
+ int64 artifact_id = 2;
+}
diff --git a/routers/api/actions/artifacts_chunks.go b/routers/api/actions/artifacts_chunks.go
index 0713c8bba8cea..3a81724b3adf3 100644
--- a/routers/api/actions/artifacts_chunks.go
+++ b/routers/api/actions/artifacts_chunks.go
@@ -5,11 +5,16 @@ package actions
import (
"crypto/md5"
+ "crypto/sha256"
"encoding/base64"
+ "encoding/hex"
+ "errors"
"fmt"
+ "hash"
"io"
"path/filepath"
"sort"
+ "strings"
"time"
"code.gitea.io/gitea/models/actions"
@@ -18,39 +23,45 @@ import (
"code.gitea.io/gitea/modules/storage"
)
-func saveUploadChunk(st storage.ObjectStorage, ctx *ArtifactContext,
+func saveUploadChunkBase(st storage.ObjectStorage, ctx *ArtifactContext,
artifact *actions.ActionArtifact,
- contentSize, runID int64,
+ contentSize, runID, start, end, length int64, checkMd5 bool,
) (int64, error) {
- // parse content-range header, format: bytes 0-1023/146515
- contentRange := ctx.Req.Header.Get("Content-Range")
- start, end, length := int64(0), int64(0), int64(0)
- if _, err := fmt.Sscanf(contentRange, "bytes %d-%d/%d", &start, &end, &length); err != nil {
- log.Warn("parse content range error: %v, content-range: %s", err, contentRange)
- return -1, fmt.Errorf("parse content range error: %v", err)
- }
// build chunk store path
storagePath := fmt.Sprintf("tmp%d/%d-%d-%d-%d.chunk", runID, runID, artifact.ID, start, end)
- // use io.TeeReader to avoid reading all body to md5 sum.
- // it writes data to hasher after reading end
- // if hash is not matched, delete the read-end result
- hasher := md5.New()
- r := io.TeeReader(ctx.Req.Body, hasher)
+ var r io.Reader = ctx.Req.Body
+ var hasher hash.Hash
+ if checkMd5 {
+ // use io.TeeReader to avoid reading all body to md5 sum.
+ // it writes data to hasher after reading end
+ // if hash is not matched, delete the read-end result
+ hasher = md5.New()
+ r = io.TeeReader(r, hasher)
+ }
// save chunk to storage
writtenSize, err := st.Save(storagePath, r, -1)
if err != nil {
return -1, fmt.Errorf("save chunk to storage error: %v", err)
}
- // check md5
- reqMd5String := ctx.Req.Header.Get(artifactXActionsResultsMD5Header)
- chunkMd5String := base64.StdEncoding.EncodeToString(hasher.Sum(nil))
- log.Info("[artifact] check chunk md5, sum: %s, header: %s", chunkMd5String, reqMd5String)
- // if md5 not match, delete the chunk
- if reqMd5String != chunkMd5String || writtenSize != contentSize {
+ var checkErr error
+ if checkMd5 {
+ // check md5
+ reqMd5String := ctx.Req.Header.Get(artifactXActionsResultsMD5Header)
+ chunkMd5String := base64.StdEncoding.EncodeToString(hasher.Sum(nil))
+ log.Info("[artifact] check chunk md5, sum: %s, header: %s", chunkMd5String, reqMd5String)
+ // if md5 not match, delete the chunk
+ if reqMd5String != chunkMd5String {
+ checkErr = fmt.Errorf("md5 not match")
+ }
+ }
+ if writtenSize != contentSize {
+ checkErr = errors.Join(checkErr, fmt.Errorf("contentSize not match body size"))
+ }
+ if checkErr != nil {
if err := st.Delete(storagePath); err != nil {
log.Error("Error deleting chunk: %s, %v", storagePath, err)
}
- return -1, fmt.Errorf("md5 not match")
+ return -1, checkErr
}
log.Info("[artifact] save chunk %s, size: %d, artifact id: %d, start: %d, end: %d",
storagePath, contentSize, artifact.ID, start, end)
@@ -58,6 +69,28 @@ func saveUploadChunk(st storage.ObjectStorage, ctx *ArtifactContext,
return length, nil
}
+func saveUploadChunk(st storage.ObjectStorage, ctx *ArtifactContext,
+ artifact *actions.ActionArtifact,
+ contentSize, runID int64,
+) (int64, error) {
+ // parse content-range header, format: bytes 0-1023/146515
+ contentRange := ctx.Req.Header.Get("Content-Range")
+ start, end, length := int64(0), int64(0), int64(0)
+ if _, err := fmt.Sscanf(contentRange, "bytes %d-%d/%d", &start, &end, &length); err != nil {
+ log.Warn("parse content range error: %v, content-range: %s", err, contentRange)
+ return -1, fmt.Errorf("parse content range error: %v", err)
+ }
+ return saveUploadChunkBase(st, ctx, artifact, contentSize, runID, start, end, length, true)
+}
+
+func appendUploadChunk(st storage.ObjectStorage, ctx *ArtifactContext,
+ artifact *actions.ActionArtifact,
+ start, contentSize, runID int64,
+) (int64, error) {
+ end := start + contentSize - 1
+ return saveUploadChunkBase(st, ctx, artifact, contentSize, runID, start, end, contentSize, false)
+}
+
type chunkFileItem struct {
RunID int64
ArtifactID int64
@@ -111,14 +144,14 @@ func mergeChunksForRun(ctx *ArtifactContext, st storage.ObjectStorage, runID int
log.Debug("artifact %d chunks not found", art.ID)
continue
}
- if err := mergeChunksForArtifact(ctx, chunks, st, art); err != nil {
+ if err := mergeChunksForArtifact(ctx, chunks, st, art, ""); err != nil {
return err
}
}
return nil
}
-func mergeChunksForArtifact(ctx *ArtifactContext, chunks []*chunkFileItem, st storage.ObjectStorage, artifact *actions.ActionArtifact) error {
+func mergeChunksForArtifact(ctx *ArtifactContext, chunks []*chunkFileItem, st storage.ObjectStorage, artifact *actions.ActionArtifact, checksum string) error {
sort.Slice(chunks, func(i, j int) bool {
return chunks[i].Start < chunks[j].Start
})
@@ -157,6 +190,14 @@ func mergeChunksForArtifact(ctx *ArtifactContext, chunks []*chunkFileItem, st st
readers = append(readers, readCloser)
}
mergedReader := io.MultiReader(readers...)
+ shaPrefix := "sha256:"
+ var hash hash.Hash
+ if strings.HasPrefix(checksum, shaPrefix) {
+ hash = sha256.New()
+ }
+ if hash != nil {
+ mergedReader = io.TeeReader(mergedReader, hash)
+ }
// if chunk is gzip, use gz as extension
// download-artifact action will use content-encoding header to decide if it should decompress the file
@@ -185,6 +226,14 @@ func mergeChunksForArtifact(ctx *ArtifactContext, chunks []*chunkFileItem, st st
}
}()
+ if hash != nil {
+ rawChecksum := hash.Sum(nil)
+ actualChecksum := hex.EncodeToString(rawChecksum)
+ if !strings.HasSuffix(checksum, actualChecksum) {
+ return fmt.Errorf("update artifact error checksum is invalid")
+ }
+ }
+
// save storage path to artifact
log.Debug("[artifact] merge chunks to artifact: %d, %s, old:%s", artifact.ID, storagePath, artifact.StoragePath)
// if artifact is already uploaded, delete the old file
diff --git a/routers/api/actions/artifacts_utils.go b/routers/api/actions/artifacts_utils.go
index 381e7eb16ee95..aaf89ef40e6d3 100644
--- a/routers/api/actions/artifacts_utils.go
+++ b/routers/api/actions/artifacts_utils.go
@@ -43,6 +43,17 @@ func validateRunID(ctx *ArtifactContext) (*actions.ActionTask, int64, bool) {
return task, runID, true
}
+func validateRunIDV4(ctx *ArtifactContext, rawRunID string) (*actions.ActionTask, int64, bool) {
+ task := ctx.ActionTask
+ runID, err := strconv.ParseInt(rawRunID, 10, 64)
+ if err != nil || task.Job.RunID != runID {
+ log.Error("Error runID not match")
+ ctx.Error(http.StatusBadRequest, "run-id does not match")
+ return nil, 0, false
+ }
+ return task, runID, true
+}
+
func validateArtifactHash(ctx *ArtifactContext, artifactName string) bool {
paramHash := ctx.Params("artifact_hash")
// use artifact name to create upload url
diff --git a/routers/api/actions/artifactsv4.go b/routers/api/actions/artifactsv4.go
new file mode 100644
index 0000000000000..8300989c75ce5
--- /dev/null
+++ b/routers/api/actions/artifactsv4.go
@@ -0,0 +1,512 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package actions
+
+// GitHub Actions Artifacts V4 API Simple Description
+//
+// 1. Upload artifact
+// 1.1. CreateArtifact
+// Post: /twirp/github.actions.results.api.v1.ArtifactService/CreateArtifact
+// Request:
+// {
+// "workflow_run_backend_id": "21",
+// "workflow_job_run_backend_id": "49",
+// "name": "test",
+// "version": 4
+// }
+// Response:
+// {
+// "ok": true,
+// "signedUploadUrl": "http://localhost:3000/twirp/github.actions.results.api.v1.ArtifactService/UploadArtifact?sig=mO7y35r4GyjN7fwg0DTv3-Fv1NDXD84KLEgLpoPOtDI=&expires=2024-01-23+21%3A48%3A37.20833956+%2B0100+CET&artifactName=test&taskID=75"
+// }
+// 1.2. Upload Zip Content to Blobstorage (unauthenticated request)
+// PUT: http://localhost:3000/twirp/github.actions.results.api.v1.ArtifactService/UploadArtifact?sig=mO7y35r4GyjN7fwg0DTv3-Fv1NDXD84KLEgLpoPOtDI=&expires=2024-01-23+21%3A48%3A37.20833956+%2B0100+CET&artifactName=test&taskID=75&comp=block
+// 1.3. Continue Upload Zip Content to Blobstorage (unauthenticated request), repeat until everything is uploaded
+// PUT: http://localhost:3000/twirp/github.actions.results.api.v1.ArtifactService/UploadArtifact?sig=mO7y35r4GyjN7fwg0DTv3-Fv1NDXD84KLEgLpoPOtDI=&expires=2024-01-23+21%3A48%3A37.20833956+%2B0100+CET&artifactName=test&taskID=75&comp=appendBlock
+// 1.4. Unknown xml payload to Blobstorage (unauthenticated request), ignored for now
+// PUT: http://localhost:3000/twirp/github.actions.results.api.v1.ArtifactService/UploadArtifact?sig=mO7y35r4GyjN7fwg0DTv3-Fv1NDXD84KLEgLpoPOtDI=&expires=2024-01-23+21%3A48%3A37.20833956+%2B0100+CET&artifactName=test&taskID=75&comp=blockList
+// 1.5. FinalizeArtifact
+// Post: /twirp/github.actions.results.api.v1.ArtifactService/FinalizeArtifact
+// Request
+// {
+// "workflow_run_backend_id": "21",
+// "workflow_job_run_backend_id": "49",
+// "name": "test",
+// "size": "2097",
+// "hash": "sha256:b6325614d5649338b87215d9536b3c0477729b8638994c74cdefacb020a2cad4"
+// }
+// Response
+// {
+// "ok": true,
+// "artifactId": "4"
+// }
+// 2. Download artifact
+// 2.1. ListArtifacts and optionally filter by artifact exact name or id
+// Post: /twirp/github.actions.results.api.v1.ArtifactService/ListArtifacts
+// Request
+// {
+// "workflow_run_backend_id": "21",
+// "workflow_job_run_backend_id": "49",
+// "name_filter": "test"
+// }
+// Response
+// {
+// "artifacts": [
+// {
+// "workflowRunBackendId": "21",
+// "workflowJobRunBackendId": "49",
+// "databaseId": "4",
+// "name": "test",
+// "size": "2093",
+// "createdAt": "2024-01-23T00:13:28Z"
+// }
+// ]
+// }
+// 2.2. GetSignedArtifactURL get the URL to download the artifact zip file of a specific artifact
+// Post: /twirp/github.actions.results.api.v1.ArtifactService/GetSignedArtifactURL
+// Request
+// {
+// "workflow_run_backend_id": "21",
+// "workflow_job_run_backend_id": "49",
+// "name": "test"
+// }
+// Response
+// {
+// "signedUrl": "http://localhost:3000/twirp/github.actions.results.api.v1.ArtifactService/DownloadArtifact?sig=wHzFOwpF-6220-5CA0CIRmAX9VbiTC2Mji89UOqo1E8=&expires=2024-01-23+21%3A51%3A56.872846295+%2B0100+CET&artifactName=test&taskID=76"
+// }
+// 2.3. Download Zip from Blobstorage (unauthenticated request)
+// GET: http://localhost:3000/twirp/github.actions.results.api.v1.ArtifactService/DownloadArtifact?sig=wHzFOwpF-6220-5CA0CIRmAX9VbiTC2Mji89UOqo1E8=&expires=2024-01-23+21%3A51%3A56.872846295+%2B0100+CET&artifactName=test&taskID=76
+
+import (
+ "crypto/hmac"
+ "crypto/sha256"
+ "encoding/base64"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "strconv"
+ "strings"
+ "time"
+
+ "code.gitea.io/gitea/models/actions"
+ "code.gitea.io/gitea/models/db"
+ "code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/storage"
+ "code.gitea.io/gitea/modules/util"
+ "code.gitea.io/gitea/modules/web"
+ "code.gitea.io/gitea/services/context"
+
+ "google.golang.org/protobuf/encoding/protojson"
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ "google.golang.org/protobuf/types/known/timestamppb"
+)
+
+const (
+ ArtifactV4RouteBase = "/twirp/github.actions.results.api.v1.ArtifactService"
+ ArtifactV4ContentEncoding = "application/zip"
+)
+
+type artifactV4Routes struct {
+ prefix string
+ fs storage.ObjectStorage
+}
+
+func ArtifactV4Contexter() func(next http.Handler) http.Handler {
+ return func(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
+ base, baseCleanUp := context.NewBaseContext(resp, req)
+ defer baseCleanUp()
+
+ ctx := &ArtifactContext{Base: base}
+ ctx.AppendContextValue(artifactContextKey, ctx)
+
+ next.ServeHTTP(ctx.Resp, ctx.Req)
+ })
+ }
+}
+
+func ArtifactsV4Routes(prefix string) *web.Route {
+ m := web.NewRoute()
+
+ r := artifactV4Routes{
+ prefix: prefix,
+ fs: storage.ActionsArtifacts,
+ }
+
+ m.Group("", func() {
+ m.Post("CreateArtifact", r.createArtifact)
+ m.Post("FinalizeArtifact", r.finalizeArtifact)
+ m.Post("ListArtifacts", r.listArtifacts)
+ m.Post("GetSignedArtifactURL", r.getSignedArtifactURL)
+ m.Post("DeleteArtifact", r.deleteArtifact)
+ }, ArtifactContexter())
+ m.Group("", func() {
+ m.Put("UploadArtifact", r.uploadArtifact)
+ m.Get("DownloadArtifact", r.downloadArtifact)
+ }, ArtifactV4Contexter())
+
+ return m
+}
+
+func (r artifactV4Routes) buildSignature(endp, expires, artifactName string, taskID int64) []byte {
+ mac := hmac.New(sha256.New, setting.GetGeneralTokenSigningSecret())
+ mac.Write([]byte(endp))
+ mac.Write([]byte(expires))
+ mac.Write([]byte(artifactName))
+ mac.Write([]byte(fmt.Sprint(taskID)))
+ return mac.Sum(nil)
+}
+
+func (r artifactV4Routes) buildArtifactURL(endp, artifactName string, taskID int64) string {
+ expires := time.Now().Add(60 * time.Minute).Format("2006-01-02 15:04:05.999999999 -0700 MST")
+ uploadURL := strings.TrimSuffix(setting.AppURL, "/") + strings.TrimSuffix(r.prefix, "/") +
+ "/" + endp + "?sig=" + base64.URLEncoding.EncodeToString(r.buildSignature(endp, expires, artifactName, taskID)) + "&expires=" + url.QueryEscape(expires) + "&artifactName=" + url.QueryEscape(artifactName) + "&taskID=" + fmt.Sprint(taskID)
+ return uploadURL
+}
+
+func (r artifactV4Routes) verifySignature(ctx *ArtifactContext, endp string) (*actions.ActionTask, string, bool) {
+ rawTaskID := ctx.Req.URL.Query().Get("taskID")
+ sig := ctx.Req.URL.Query().Get("sig")
+ expires := ctx.Req.URL.Query().Get("expires")
+ artifactName := ctx.Req.URL.Query().Get("artifactName")
+ dsig, _ := base64.URLEncoding.DecodeString(sig)
+ taskID, _ := strconv.ParseInt(rawTaskID, 10, 64)
+
+ expecedsig := r.buildSignature(endp, expires, artifactName, taskID)
+ if !hmac.Equal(dsig, expecedsig) {
+ log.Error("Error unauthorized")
+ ctx.Error(http.StatusUnauthorized, "Error unauthorized")
+ return nil, "", false
+ }
+ t, err := time.Parse("2006-01-02 15:04:05.999999999 -0700 MST", expires)
+ if err != nil || t.Before(time.Now()) {
+ log.Error("Error link expired")
+ ctx.Error(http.StatusUnauthorized, "Error link expired")
+ return nil, "", false
+ }
+ task, err := actions.GetTaskByID(ctx, taskID)
+ if err != nil {
+ log.Error("Error runner api getting task by ID: %v", err)
+ ctx.Error(http.StatusInternalServerError, "Error runner api getting task by ID")
+ return nil, "", false
+ }
+ if task.Status != actions.StatusRunning {
+ log.Error("Error runner api getting task: task is not running")
+ ctx.Error(http.StatusInternalServerError, "Error runner api getting task: task is not running")
+ return nil, "", false
+ }
+ if err := task.LoadJob(ctx); err != nil {
+ log.Error("Error runner api getting job: %v", err)
+ ctx.Error(http.StatusInternalServerError, "Error runner api getting job")
+ return nil, "", false
+ }
+ return task, artifactName, true
+}
+
+func (r *artifactV4Routes) getArtifactByName(ctx *ArtifactContext, runID int64, name string) (*actions.ActionArtifact, error) {
+ var art actions.ActionArtifact
+ has, err := db.GetEngine(ctx).Where("run_id = ? AND artifact_name = ? AND artifact_path = ? AND content_encoding = ?", runID, name, name+".zip", ArtifactV4ContentEncoding).Get(&art)
+ if err != nil {
+ return nil, err
+ } else if !has {
+ return nil, util.ErrNotExist
+ }
+ return &art, nil
+}
+
+func (r *artifactV4Routes) parseProtbufBody(ctx *ArtifactContext, req protoreflect.ProtoMessage) bool {
+ body, err := io.ReadAll(ctx.Req.Body)
+ if err != nil {
+ log.Error("Error decode request body: %v", err)
+ ctx.Error(http.StatusInternalServerError, "Error decode request body")
+ return false
+ }
+ err = protojson.Unmarshal(body, req)
+ if err != nil {
+ log.Error("Error decode request body: %v", err)
+ ctx.Error(http.StatusInternalServerError, "Error decode request body")
+ return false
+ }
+ return true
+}
+
+func (r *artifactV4Routes) sendProtbufBody(ctx *ArtifactContext, req protoreflect.ProtoMessage) {
+ resp, err := protojson.Marshal(req)
+ if err != nil {
+ log.Error("Error encode response body: %v", err)
+ ctx.Error(http.StatusInternalServerError, "Error encode response body")
+ return
+ }
+ ctx.Resp.Header().Set("Content-Type", "application/json;charset=utf-8")
+ ctx.Resp.WriteHeader(http.StatusOK)
+ _, _ = ctx.Resp.Write(resp)
+}
+
+func (r *artifactV4Routes) createArtifact(ctx *ArtifactContext) {
+ var req CreateArtifactRequest
+
+ if ok := r.parseProtbufBody(ctx, &req); !ok {
+ return
+ }
+ _, _, ok := validateRunIDV4(ctx, req.WorkflowRunBackendId)
+ if !ok {
+ return
+ }
+
+ artifactName := req.Name
+
+ rententionDays := setting.Actions.ArtifactRetentionDays
+ if req.ExpiresAt != nil {
+ rententionDays = int64(time.Until(req.ExpiresAt.AsTime()).Hours() / 24)
+ }
+ // create or get artifact with name and path
+ artifact, err := actions.CreateArtifact(ctx, ctx.ActionTask, artifactName, artifactName+".zip", rententionDays)
+ if err != nil {
+ log.Error("Error create or get artifact: %v", err)
+ ctx.Error(http.StatusInternalServerError, "Error create or get artifact")
+ return
+ }
+ artifact.ContentEncoding = ArtifactV4ContentEncoding
+ if err := actions.UpdateArtifactByID(ctx, artifact.ID, artifact); err != nil {
+ log.Error("Error UpdateArtifactByID: %v", err)
+ ctx.Error(http.StatusInternalServerError, "Error UpdateArtifactByID")
+ return
+ }
+
+ respData := CreateArtifactResponse{
+ Ok: true,
+ SignedUploadUrl: r.buildArtifactURL("UploadArtifact", artifactName, ctx.ActionTask.ID),
+ }
+ r.sendProtbufBody(ctx, &respData)
+}
+
+func (r *artifactV4Routes) uploadArtifact(ctx *ArtifactContext) {
+ task, artifactName, ok := r.verifySignature(ctx, "UploadArtifact")
+ if !ok {
+ return
+ }
+
+ comp := ctx.Req.URL.Query().Get("comp")
+ switch comp {
+ case "block", "appendBlock":
+ // get artifact by name
+ artifact, err := r.getArtifactByName(ctx, task.Job.RunID, artifactName)
+ if err != nil {
+ log.Error("Error artifact not found: %v", err)
+ ctx.Error(http.StatusNotFound, "Error artifact not found")
+ return
+ }
+
+ if comp == "block" {
+ artifact.FileSize = 0
+ artifact.FileCompressedSize = 0
+ }
+
+ _, err = appendUploadChunk(r.fs, ctx, artifact, artifact.FileSize, ctx.Req.ContentLength, artifact.RunID)
+ if err != nil {
+ log.Error("Error runner api getting task: task is not running")
+ ctx.Error(http.StatusInternalServerError, "Error runner api getting task: task is not running")
+ return
+ }
+ artifact.FileCompressedSize += ctx.Req.ContentLength
+ artifact.FileSize += ctx.Req.ContentLength
+ if err := actions.UpdateArtifactByID(ctx, artifact.ID, artifact); err != nil {
+ log.Error("Error UpdateArtifactByID: %v", err)
+ ctx.Error(http.StatusInternalServerError, "Error UpdateArtifactByID")
+ return
+ }
+ ctx.JSON(http.StatusCreated, "appended")
+ case "blocklist":
+ ctx.JSON(http.StatusCreated, "created")
+ }
+}
+
+func (r *artifactV4Routes) finalizeArtifact(ctx *ArtifactContext) {
+ var req FinalizeArtifactRequest
+
+ if ok := r.parseProtbufBody(ctx, &req); !ok {
+ return
+ }
+ _, runID, ok := validateRunIDV4(ctx, req.WorkflowRunBackendId)
+ if !ok {
+ return
+ }
+
+ // get artifact by name
+ artifact, err := r.getArtifactByName(ctx, runID, req.Name)
+ if err != nil {
+ log.Error("Error artifact not found: %v", err)
+ ctx.Error(http.StatusNotFound, "Error artifact not found")
+ return
+ }
+ chunkMap, err := listChunksByRunID(r.fs, runID)
+ if err != nil {
+ log.Error("Error merge chunks: %v", err)
+ ctx.Error(http.StatusInternalServerError, "Error merge chunks")
+ return
+ }
+ chunks, ok := chunkMap[artifact.ID]
+ if !ok {
+ log.Error("Error merge chunks")
+ ctx.Error(http.StatusInternalServerError, "Error merge chunks")
+ return
+ }
+ checksum := ""
+ if req.Hash != nil {
+ checksum = req.Hash.Value
+ }
+ if err := mergeChunksForArtifact(ctx, chunks, r.fs, artifact, checksum); err != nil {
+ log.Error("Error merge chunks: %v", err)
+ ctx.Error(http.StatusInternalServerError, "Error merge chunks")
+ return
+ }
+
+ respData := FinalizeArtifactResponse{
+ Ok: true,
+ ArtifactId: artifact.ID,
+ }
+ r.sendProtbufBody(ctx, &respData)
+}
+
+func (r *artifactV4Routes) listArtifacts(ctx *ArtifactContext) {
+ var req ListArtifactsRequest
+
+ if ok := r.parseProtbufBody(ctx, &req); !ok {
+ return
+ }
+ _, runID, ok := validateRunIDV4(ctx, req.WorkflowRunBackendId)
+ if !ok {
+ return
+ }
+
+ artifacts, err := db.Find[actions.ActionArtifact](ctx, actions.FindArtifactsOptions{RunID: runID})
+ if err != nil {
+ log.Error("Error getting artifacts: %v", err)
+ ctx.Error(http.StatusInternalServerError, err.Error())
+ return
+ }
+ if len(artifacts) == 0 {
+ log.Debug("[artifact] handleListArtifacts, no artifacts")
+ ctx.Error(http.StatusNotFound)
+ return
+ }
+
+ list := []*ListArtifactsResponse_MonolithArtifact{}
+
+ table := map[string]*ListArtifactsResponse_MonolithArtifact{}
+ for _, artifact := range artifacts {
+ if _, ok := table[artifact.ArtifactName]; ok || req.IdFilter != nil && artifact.ID != req.IdFilter.Value || req.NameFilter != nil && artifact.ArtifactName != req.NameFilter.Value || artifact.ArtifactName+".zip" != artifact.ArtifactPath || artifact.ContentEncoding != ArtifactV4ContentEncoding {
+ table[artifact.ArtifactName] = nil
+ continue
+ }
+
+ table[artifact.ArtifactName] = &ListArtifactsResponse_MonolithArtifact{
+ Name: artifact.ArtifactName,
+ CreatedAt: timestamppb.New(artifact.CreatedUnix.AsTime()),
+ DatabaseId: artifact.ID,
+ WorkflowRunBackendId: req.WorkflowRunBackendId,
+ WorkflowJobRunBackendId: req.WorkflowJobRunBackendId,
+ Size: artifact.FileSize,
+ }
+ }
+ for _, artifact := range table {
+ if artifact != nil {
+ list = append(list, artifact)
+ }
+ }
+
+ respData := ListArtifactsResponse{
+ Artifacts: list,
+ }
+ r.sendProtbufBody(ctx, &respData)
+}
+
+func (r *artifactV4Routes) getSignedArtifactURL(ctx *ArtifactContext) {
+ var req GetSignedArtifactURLRequest
+
+ if ok := r.parseProtbufBody(ctx, &req); !ok {
+ return
+ }
+ _, runID, ok := validateRunIDV4(ctx, req.WorkflowRunBackendId)
+ if !ok {
+ return
+ }
+
+ artifactName := req.Name
+
+ // get artifact by name
+ artifact, err := r.getArtifactByName(ctx, runID, artifactName)
+ if err != nil {
+ log.Error("Error artifact not found: %v", err)
+ ctx.Error(http.StatusNotFound, "Error artifact not found")
+ return
+ }
+
+ respData := GetSignedArtifactURLResponse{}
+
+ if setting.Actions.ArtifactStorage.MinioConfig.ServeDirect {
+ u, err := storage.ActionsArtifacts.URL(artifact.StoragePath, artifact.ArtifactPath)
+ if u != nil && err == nil {
+ respData.SignedUrl = u.String()
+ }
+ }
+ if respData.SignedUrl == "" {
+ respData.SignedUrl = r.buildArtifactURL("DownloadArtifact", artifactName, ctx.ActionTask.ID)
+ }
+ r.sendProtbufBody(ctx, &respData)
+}
+
+func (r *artifactV4Routes) downloadArtifact(ctx *ArtifactContext) {
+ task, artifactName, ok := r.verifySignature(ctx, "DownloadArtifact")
+ if !ok {
+ return
+ }
+
+ // get artifact by name
+ artifact, err := r.getArtifactByName(ctx, task.Job.RunID, artifactName)
+ if err != nil {
+ log.Error("Error artifact not found: %v", err)
+ ctx.Error(http.StatusNotFound, "Error artifact not found")
+ return
+ }
+
+ file, _ := r.fs.Open(artifact.StoragePath)
+
+ _, _ = io.Copy(ctx.Resp, file)
+}
+
+func (r *artifactV4Routes) deleteArtifact(ctx *ArtifactContext) {
+ var req DeleteArtifactRequest
+
+ if ok := r.parseProtbufBody(ctx, &req); !ok {
+ return
+ }
+ _, runID, ok := validateRunIDV4(ctx, req.WorkflowRunBackendId)
+ if !ok {
+ return
+ }
+
+ // get artifact by name
+ artifact, err := r.getArtifactByName(ctx, runID, req.Name)
+ if err != nil {
+ log.Error("Error artifact not found: %v", err)
+ ctx.Error(http.StatusNotFound, "Error artifact not found")
+ return
+ }
+
+ err = actions.SetArtifactNeedDelete(ctx, runID, req.Name)
+ if err != nil {
+ log.Error("Error deleting artifacts: %v", err)
+ ctx.Error(http.StatusInternalServerError, err.Error())
+ return
+ }
+
+ respData := DeleteArtifactResponse{
+ Ok: true,
+ ArtifactId: artifact.ID,
+ }
+ r.sendProtbufBody(ctx, &respData)
+}
diff --git a/routers/api/packages/cargo/cargo.go b/routers/api/packages/cargo/cargo.go
index d01a13d78f67c..140e532efd822 100644
--- a/routers/api/packages/cargo/cargo.go
+++ b/routers/api/packages/cargo/cargo.go
@@ -13,6 +13,7 @@ import (
"code.gitea.io/gitea/models/db"
packages_model "code.gitea.io/gitea/models/packages"
"code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/optional"
packages_module "code.gitea.io/gitea/modules/packages"
cargo_module "code.gitea.io/gitea/modules/packages/cargo"
"code.gitea.io/gitea/modules/setting"
@@ -110,7 +111,7 @@ func SearchPackages(ctx *context.Context) {
OwnerID: ctx.Package.Owner.ID,
Type: packages_model.TypeCargo,
Name: packages_model.SearchValue{Value: ctx.FormTrim("q")},
- IsInternal: util.OptionalBoolFalse,
+ IsInternal: optional.Some(false),
Paginator: &paginator,
},
)
diff --git a/routers/api/packages/chef/chef.go b/routers/api/packages/chef/chef.go
index 720fce0a2a5d7..b49f4e9d0aa8e 100644
--- a/routers/api/packages/chef/chef.go
+++ b/routers/api/packages/chef/chef.go
@@ -15,6 +15,7 @@ import (
"code.gitea.io/gitea/models/db"
packages_model "code.gitea.io/gitea/models/packages"
+ "code.gitea.io/gitea/modules/optional"
packages_module "code.gitea.io/gitea/modules/packages"
chef_module "code.gitea.io/gitea/modules/packages/chef"
"code.gitea.io/gitea/modules/setting"
@@ -40,7 +41,7 @@ func PackagesUniverse(ctx *context.Context) {
pvs, _, err := packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{
OwnerID: ctx.Package.Owner.ID,
Type: packages_model.TypeChef,
- IsInternal: util.OptionalBoolFalse,
+ IsInternal: optional.Some(false),
})
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
@@ -85,7 +86,7 @@ func EnumeratePackages(ctx *context.Context) {
OwnerID: ctx.Package.Owner.ID,
Type: packages_model.TypeChef,
Name: packages_model.SearchValue{Value: ctx.FormTrim("q")},
- IsInternal: util.OptionalBoolFalse,
+ IsInternal: optional.Some(false),
Paginator: db.NewAbsoluteListOptions(
ctx.FormInt("start"),
ctx.FormInt("items"),
diff --git a/routers/api/packages/composer/composer.go b/routers/api/packages/composer/composer.go
index 346408d2611ba..a045da40def92 100644
--- a/routers/api/packages/composer/composer.go
+++ b/routers/api/packages/composer/composer.go
@@ -14,6 +14,7 @@ import (
"code.gitea.io/gitea/models/db"
packages_model "code.gitea.io/gitea/models/packages"
+ "code.gitea.io/gitea/modules/optional"
packages_module "code.gitea.io/gitea/modules/packages"
composer_module "code.gitea.io/gitea/modules/packages/composer"
"code.gitea.io/gitea/modules/setting"
@@ -66,7 +67,7 @@ func SearchPackages(ctx *context.Context) {
OwnerID: ctx.Package.Owner.ID,
Type: packages_model.TypeComposer,
Name: packages_model.SearchValue{Value: ctx.FormTrim("q")},
- IsInternal: util.OptionalBoolFalse,
+ IsInternal: optional.Some(false),
Paginator: &paginator,
}
if ctx.FormTrim("type") != "" {
diff --git a/routers/api/packages/goproxy/goproxy.go b/routers/api/packages/goproxy/goproxy.go
index 9eb515d9a1bef..d658066bb4371 100644
--- a/routers/api/packages/goproxy/goproxy.go
+++ b/routers/api/packages/goproxy/goproxy.go
@@ -12,6 +12,7 @@ import (
"time"
packages_model "code.gitea.io/gitea/models/packages"
+ "code.gitea.io/gitea/modules/optional"
packages_module "code.gitea.io/gitea/modules/packages"
goproxy_module "code.gitea.io/gitea/modules/packages/goproxy"
"code.gitea.io/gitea/modules/util"
@@ -129,7 +130,7 @@ func resolvePackage(ctx *context.Context, ownerID int64, name, version string) (
Value: name,
ExactMatch: true,
},
- IsInternal: util.OptionalBoolFalse,
+ IsInternal: optional.Some(false),
Sort: packages_model.SortCreatedDesc,
})
if err != nil {
diff --git a/routers/api/packages/helm/helm.go b/routers/api/packages/helm/helm.go
index e7a346d9ca7be..efdb83ec0e776 100644
--- a/routers/api/packages/helm/helm.go
+++ b/routers/api/packages/helm/helm.go
@@ -15,6 +15,7 @@ import (
packages_model "code.gitea.io/gitea/models/packages"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/optional"
packages_module "code.gitea.io/gitea/modules/packages"
helm_module "code.gitea.io/gitea/modules/packages/helm"
"code.gitea.io/gitea/modules/setting"
@@ -42,7 +43,7 @@ func Index(ctx *context.Context) {
pvs, _, err := packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{
OwnerID: ctx.Package.Owner.ID,
Type: packages_model.TypeHelm,
- IsInternal: util.OptionalBoolFalse,
+ IsInternal: optional.Some(false),
})
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
@@ -110,7 +111,7 @@ func DownloadPackageFile(ctx *context.Context) {
Value: ctx.Params("package"),
},
HasFileWithName: filename,
- IsInternal: util.OptionalBoolFalse,
+ IsInternal: optional.Some(false),
})
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
diff --git a/routers/api/packages/npm/api.go b/routers/api/packages/npm/api.go
index 8470874884238..f8e839c42412e 100644
--- a/routers/api/packages/npm/api.go
+++ b/routers/api/packages/npm/api.go
@@ -12,6 +12,7 @@ import (
packages_model "code.gitea.io/gitea/models/packages"
npm_module "code.gitea.io/gitea/modules/packages/npm"
+ "code.gitea.io/gitea/modules/setting"
)
func createPackageMetadataResponse(registryURL string, pds []*packages_model.PackageDescriptor) *npm_module.PackageMetadata {
@@ -98,7 +99,7 @@ func createPackageSearchResponse(pds []*packages_model.PackageDescriptor, total
Maintainers: []npm_module.User{}, // npm cli needs this field
Keywords: metadata.Keywords,
Links: &npm_module.PackageSearchPackageLinks{
- Registry: pd.FullWebLink(),
+ Registry: setting.AppURL + "api/packages/" + pd.Owner.Name + "/npm",
Homepage: metadata.ProjectURL,
},
},
diff --git a/routers/api/packages/npm/npm.go b/routers/api/packages/npm/npm.go
index 72b4305928111..84acfffae25e2 100644
--- a/routers/api/packages/npm/npm.go
+++ b/routers/api/packages/npm/npm.go
@@ -17,6 +17,7 @@ import (
access_model "code.gitea.io/gitea/models/perm/access"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
+ "code.gitea.io/gitea/modules/optional"
packages_module "code.gitea.io/gitea/modules/packages"
npm_module "code.gitea.io/gitea/modules/packages/npm"
"code.gitea.io/gitea/modules/setting"
@@ -120,7 +121,7 @@ func DownloadPackageFileByName(ctx *context.Context) {
Value: packageNameFromParams(ctx),
},
HasFileWithName: filename,
- IsInternal: util.OptionalBoolFalse,
+ IsInternal: optional.Some(false),
})
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
@@ -395,7 +396,7 @@ func setPackageTag(ctx std_ctx.Context, tag string, pv *packages_model.PackageVe
Properties: map[string]string{
npm_module.TagProperty: tag,
},
- IsInternal: util.OptionalBoolFalse,
+ IsInternal: optional.Some(false),
})
if err != nil {
return err
@@ -431,7 +432,7 @@ func PackageSearch(ctx *context.Context) {
pvs, total, err := packages_model.SearchLatestVersions(ctx, &packages_model.PackageSearchOptions{
OwnerID: ctx.Package.Owner.ID,
Type: packages_model.TypeNpm,
- IsInternal: util.OptionalBoolFalse,
+ IsInternal: optional.Some(false),
Name: packages_model.SearchValue{
ExactMatch: false,
Value: ctx.FormTrim("text"),
diff --git a/routers/api/packages/nuget/nuget.go b/routers/api/packages/nuget/nuget.go
index a0273aad5ad33..c28bc6c9d9233 100644
--- a/routers/api/packages/nuget/nuget.go
+++ b/routers/api/packages/nuget/nuget.go
@@ -18,6 +18,7 @@ import (
packages_model "code.gitea.io/gitea/models/packages"
nuget_model "code.gitea.io/gitea/models/packages/nuget"
"code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/optional"
packages_module "code.gitea.io/gitea/modules/packages"
nuget_module "code.gitea.io/gitea/modules/packages/nuget"
"code.gitea.io/gitea/modules/setting"
@@ -122,7 +123,7 @@ func SearchServiceV2(ctx *context.Context) {
Name: packages_model.SearchValue{
Value: getSearchTerm(ctx),
},
- IsInternal: util.OptionalBoolFalse,
+ IsInternal: optional.Some(false),
Paginator: paginator,
})
if err != nil {
@@ -172,7 +173,7 @@ func SearchServiceV2Count(ctx *context.Context) {
Name: packages_model.SearchValue{
Value: getSearchTerm(ctx),
},
- IsInternal: util.OptionalBoolFalse,
+ IsInternal: optional.Some(false),
})
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
@@ -187,7 +188,7 @@ func SearchServiceV3(ctx *context.Context) {
pvs, count, err := nuget_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{
OwnerID: ctx.Package.Owner.ID,
Name: packages_model.SearchValue{Value: ctx.FormTrim("q")},
- IsInternal: util.OptionalBoolFalse,
+ IsInternal: optional.Some(false),
Paginator: db.NewAbsoluteListOptions(
ctx.FormInt("skip"),
ctx.FormInt("take"),
@@ -313,7 +314,7 @@ func EnumeratePackageVersionsV2(ctx *context.Context) {
ExactMatch: true,
Value: packageName,
},
- IsInternal: util.OptionalBoolFalse,
+ IsInternal: optional.Some(false),
Paginator: paginator,
})
if err != nil {
@@ -358,7 +359,7 @@ func EnumeratePackageVersionsV2Count(ctx *context.Context) {
ExactMatch: true,
Value: strings.Trim(ctx.FormTrim("id"), "'"),
},
- IsInternal: util.OptionalBoolFalse,
+ IsInternal: optional.Some(false),
})
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
diff --git a/routers/api/packages/rubygems/rubygems.go b/routers/api/packages/rubygems/rubygems.go
index 5d05b6d524d51..d2fbcd01f06bf 100644
--- a/routers/api/packages/rubygems/rubygems.go
+++ b/routers/api/packages/rubygems/rubygems.go
@@ -13,6 +13,7 @@ import (
"strings"
packages_model "code.gitea.io/gitea/models/packages"
+ "code.gitea.io/gitea/modules/optional"
packages_module "code.gitea.io/gitea/modules/packages"
rubygems_module "code.gitea.io/gitea/modules/packages/rubygems"
"code.gitea.io/gitea/modules/util"
@@ -43,7 +44,7 @@ func EnumeratePackagesLatest(ctx *context.Context) {
pvs, _, err := packages_model.SearchLatestVersions(ctx, &packages_model.PackageSearchOptions{
OwnerID: ctx.Package.Owner.ID,
Type: packages_model.TypeRubyGems,
- IsInternal: util.OptionalBoolFalse,
+ IsInternal: optional.Some(false),
})
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
@@ -304,7 +305,7 @@ func getVersionsByFilename(ctx *context.Context, filename string) ([]*packages_m
OwnerID: ctx.Package.Owner.ID,
Type: packages_model.TypeRubyGems,
HasFileWithName: filename,
- IsInternal: util.OptionalBoolFalse,
+ IsInternal: optional.Some(false),
})
return pvs, err
}
diff --git a/routers/api/packages/swift/swift.go b/routers/api/packages/swift/swift.go
index 1fc8baeaacd6a..a9da3ea9c2d86 100644
--- a/routers/api/packages/swift/swift.go
+++ b/routers/api/packages/swift/swift.go
@@ -15,6 +15,7 @@ import (
packages_model "code.gitea.io/gitea/models/packages"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/optional"
packages_module "code.gitea.io/gitea/modules/packages"
swift_module "code.gitea.io/gitea/modules/packages/swift"
"code.gitea.io/gitea/modules/setting"
@@ -433,7 +434,7 @@ func LookupPackageIdentifiers(ctx *context.Context) {
Properties: map[string]string{
swift_module.PropertyRepositoryURL: url,
},
- IsInternal: util.OptionalBoolFalse,
+ IsInternal: optional.Some(false),
})
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
diff --git a/routers/api/v1/admin/hooks.go b/routers/api/v1/admin/hooks.go
index 2217d002a0206..4c168b55bf183 100644
--- a/routers/api/v1/admin/hooks.go
+++ b/routers/api/v1/admin/hooks.go
@@ -8,6 +8,7 @@ import (
"net/http"
"code.gitea.io/gitea/models/webhook"
+ "code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
@@ -37,7 +38,7 @@ func ListHooks(ctx *context.APIContext) {
// "200":
// "$ref": "#/responses/HookList"
- sysHooks, err := webhook.GetSystemWebhooks(ctx, util.OptionalBoolNone)
+ sysHooks, err := webhook.GetSystemWebhooks(ctx, optional.None[bool]())
if err != nil {
ctx.Error(http.StatusInternalServerError, "GetSystemWebhooks", err)
return
diff --git a/routers/api/v1/packages/package.go b/routers/api/v1/packages/package.go
index 3be31b13ae100..b38aa131676e1 100644
--- a/routers/api/v1/packages/package.go
+++ b/routers/api/v1/packages/package.go
@@ -7,8 +7,8 @@ import (
"net/http"
"code.gitea.io/gitea/models/packages"
+ "code.gitea.io/gitea/modules/optional"
api "code.gitea.io/gitea/modules/structs"
- "code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/routers/api/v1/utils"
"code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/convert"
@@ -60,7 +60,7 @@ func ListPackages(ctx *context.APIContext) {
OwnerID: ctx.Package.Owner.ID,
Type: packages.Type(packageType),
Name: packages.SearchValue{Value: query},
- IsInternal: util.OptionalBoolFalse,
+ IsInternal: optional.Some(false),
Paginator: &listOptions,
})
if err != nil {
diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go
index 227e0e725cfb9..1b2ecd474be1c 100644
--- a/routers/api/v1/repo/issue.go
+++ b/routers/api/v1/repo/issue.go
@@ -23,7 +23,6 @@ import (
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil"
- "code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/api/v1/utils"
"code.gitea.io/gitea/services/context"
@@ -123,14 +122,14 @@ func SearchIssues(ctx *context.APIContext) {
return
}
- var isClosed util.OptionalBool
+ var isClosed optional.Option[bool]
switch ctx.FormString("state") {
case "closed":
- isClosed = util.OptionalBoolTrue
+ isClosed = optional.Some(true)
case "all":
- isClosed = util.OptionalBoolNone
+ isClosed = optional.None[bool]()
default:
- isClosed = util.OptionalBoolFalse
+ isClosed = optional.Some(false)
}
var (
@@ -205,14 +204,14 @@ func SearchIssues(ctx *context.APIContext) {
keyword = ""
}
- var isPull util.OptionalBool
+ var isPull optional.Option[bool]
switch ctx.FormString("type") {
case "pulls":
- isPull = util.OptionalBoolTrue
+ isPull = optional.Some(true)
case "issues":
- isPull = util.OptionalBoolFalse
+ isPull = optional.Some(false)
default:
- isPull = util.OptionalBoolNone
+ isPull = optional.None[bool]()
}
var includedAnyLabels []int64
@@ -397,14 +396,14 @@ func ListIssues(ctx *context.APIContext) {
return
}
- var isClosed util.OptionalBool
+ var isClosed optional.Option[bool]
switch ctx.FormString("state") {
case "closed":
- isClosed = util.OptionalBoolTrue
+ isClosed = optional.Some(true)
case "all":
- isClosed = util.OptionalBoolNone
+ isClosed = optional.None[bool]()
default:
- isClosed = util.OptionalBoolFalse
+ isClosed = optional.Some(false)
}
keyword := ctx.FormTrim("q")
@@ -453,31 +452,29 @@ func ListIssues(ctx *context.APIContext) {
listOptions := utils.GetListOptions(ctx)
- var isPull util.OptionalBool
+ isPull := optional.None[bool]()
switch ctx.FormString("type") {
case "pulls":
- isPull = util.OptionalBoolTrue
+ isPull = optional.Some(true)
case "issues":
- isPull = util.OptionalBoolFalse
- default:
- isPull = util.OptionalBoolNone
+ isPull = optional.Some(false)
}
- if isPull != util.OptionalBoolNone && !ctx.Repo.CanReadIssuesOrPulls(isPull.IsTrue()) {
+ if isPull.Has() && !ctx.Repo.CanReadIssuesOrPulls(isPull.Value()) {
ctx.NotFound()
return
}
- if isPull == util.OptionalBoolNone {
+ if !isPull.Has() {
canReadIssues := ctx.Repo.CanRead(unit.TypeIssues)
canReadPulls := ctx.Repo.CanRead(unit.TypePullRequests)
if !canReadIssues && !canReadPulls {
ctx.NotFound()
return
} else if !canReadIssues {
- isPull = util.OptionalBoolTrue
+ isPull = optional.Some(true)
} else if !canReadPulls {
- isPull = util.OptionalBoolFalse
+ isPull = optional.Some(false)
}
}
diff --git a/routers/api/v1/repo/issue_comment.go b/routers/api/v1/repo/issue_comment.go
index 763419b7a2520..6209e960af450 100644
--- a/routers/api/v1/repo/issue_comment.go
+++ b/routers/api/v1/repo/issue_comment.go
@@ -14,8 +14,8 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/optional"
api "code.gitea.io/gitea/modules/structs"
- "code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/api/v1/utils"
"code.gitea.io/gitea/services/context"
@@ -278,15 +278,15 @@ func ListRepoIssueComments(ctx *context.APIContext) {
return
}
- var isPull util.OptionalBool
+ var isPull optional.Option[bool]
canReadIssue := ctx.Repo.CanRead(unit.TypeIssues)
canReadPull := ctx.Repo.CanRead(unit.TypePullRequests)
if canReadIssue && canReadPull {
- isPull = util.OptionalBoolNone
+ isPull = optional.None[bool]()
} else if canReadIssue {
- isPull = util.OptionalBoolFalse
+ isPull = optional.Some(false)
} else if canReadPull {
- isPull = util.OptionalBoolTrue
+ isPull = optional.Some(true)
} else {
ctx.NotFound()
return
diff --git a/routers/api/v1/repo/milestone.go b/routers/api/v1/repo/milestone.go
index d4c828fe8bf1d..b9534016e4b87 100644
--- a/routers/api/v1/repo/milestone.go
+++ b/routers/api/v1/repo/milestone.go
@@ -11,9 +11,9 @@ import (
"code.gitea.io/gitea/models/db"
issues_model "code.gitea.io/gitea/models/issues"
+ "code.gitea.io/gitea/modules/optional"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil"
- "code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/api/v1/utils"
"code.gitea.io/gitea/services/context"
@@ -61,10 +61,10 @@ func ListMilestones(ctx *context.APIContext) {
// "$ref": "#/responses/notFound"
state := api.StateType(ctx.FormString("state"))
- var isClosed util.OptionalBool
+ var isClosed optional.Option[bool]
switch state {
case api.StateClosed, api.StateOpen:
- isClosed = util.OptionalBoolOf(state == api.StateClosed)
+ isClosed = optional.Some(state == api.StateClosed)
}
milestones, total, err := db.FindAndCount[issues_model.Milestone](ctx, issues_model.FindMilestoneOptions{
diff --git a/routers/api/v1/repo/release_attachment.go b/routers/api/v1/repo/release_attachment.go
index a29bce66a4e89..59fd83e3a2793 100644
--- a/routers/api/v1/repo/release_attachment.go
+++ b/routers/api/v1/repo/release_attachment.go
@@ -4,7 +4,9 @@
package repo
import (
+ "io"
"net/http"
+ "strings"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/log"
@@ -154,6 +156,7 @@ func CreateReleaseAttachment(ctx *context.APIContext) {
// - application/json
// consumes:
// - multipart/form-data
+ // - application/octet-stream
// parameters:
// - name: owner
// in: path
@@ -180,7 +183,7 @@ func CreateReleaseAttachment(ctx *context.APIContext) {
// in: formData
// description: attachment to upload
// type: file
- // required: true
+ // required: false
// responses:
// "201":
// "$ref": "#/responses/Attachment"
@@ -202,20 +205,36 @@ func CreateReleaseAttachment(ctx *context.APIContext) {
}
// Get uploaded file from request
- file, header, err := ctx.Req.FormFile("attachment")
- if err != nil {
- ctx.Error(http.StatusInternalServerError, "GetFile", err)
- return
+ var content io.ReadCloser
+ var filename string
+ var size int64 = -1
+
+ if strings.HasPrefix(strings.ToLower(ctx.Req.Header.Get("Content-Type")), "multipart/form-data") {
+ file, header, err := ctx.Req.FormFile("attachment")
+ if err != nil {
+ ctx.Error(http.StatusInternalServerError, "GetFile", err)
+ return
+ }
+ defer file.Close()
+
+ content = file
+ size = header.Size
+ filename = header.Filename
+ if name := ctx.FormString("name"); name != "" {
+ filename = name
+ }
+ } else {
+ content = ctx.Req.Body
+ filename = ctx.FormString("name")
}
- defer file.Close()
- filename := header.Filename
- if query := ctx.FormString("name"); query != "" {
- filename = query
+ if filename == "" {
+ ctx.Error(http.StatusBadRequest, "CreateReleaseAttachment", "Could not determine name of attachment.")
+ return
}
// Create a new attachment and save the file
- attach, err := attachment.UploadAttachment(ctx, file, setting.Repository.Release.AllowedTypes, header.Size, &repo_model.Attachment{
+ attach, err := attachment.UploadAttachment(ctx, content, setting.Repository.Release.AllowedTypes, size, &repo_model.Attachment{
Name: filename,
UploaderID: ctx.Doer.ID,
RepoID: ctx.Repo.Repository.ID,
diff --git a/routers/init.go b/routers/init.go
index e0a7150ba3182..1dedbebeb5c47 100644
--- a/routers/init.go
+++ b/routers/init.go
@@ -198,6 +198,8 @@ func NormalRoutes() *web.Route {
// TODO: this prefix should be generated with a token string with runner ?
prefix = "/api/actions_pipeline"
r.Mount(prefix, actions_router.ArtifactsRoutes(prefix))
+ prefix = actions_router.ArtifactV4RouteBase
+ r.Mount(prefix, actions_router.ArtifactsV4Routes(prefix))
}
return r
diff --git a/routers/web/admin/hooks.go b/routers/web/admin/hooks.go
index 8d4c66fdb2bef..8d59fbb858e96 100644
--- a/routers/web/admin/hooks.go
+++ b/routers/web/admin/hooks.go
@@ -8,8 +8,8 @@ import (
"code.gitea.io/gitea/models/webhook"
"code.gitea.io/gitea/modules/base"
+ "code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/context"
)
@@ -35,7 +35,7 @@ func DefaultOrSystemWebhooks(ctx *context.Context) {
sys["Title"] = ctx.Tr("admin.systemhooks")
sys["Description"] = ctx.Tr("admin.systemhooks.desc")
- sys["Webhooks"], err = webhook.GetSystemWebhooks(ctx, util.OptionalBoolNone)
+ sys["Webhooks"], err = webhook.GetSystemWebhooks(ctx, optional.None[bool]())
sys["BaseLink"] = setting.AppSubURL + "/admin/hooks"
sys["BaseLinkNew"] = setting.AppSubURL + "/admin/system-hooks"
if err != nil {
diff --git a/routers/web/admin/packages.go b/routers/web/admin/packages.go
index 7c16b69a85cf7..39f064a1be637 100644
--- a/routers/web/admin/packages.go
+++ b/routers/web/admin/packages.go
@@ -11,8 +11,8 @@ import (
"code.gitea.io/gitea/models/db"
packages_model "code.gitea.io/gitea/models/packages"
"code.gitea.io/gitea/modules/base"
+ "code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/context"
packages_service "code.gitea.io/gitea/services/packages"
packages_cleanup_service "code.gitea.io/gitea/services/packages/cleanup"
@@ -36,7 +36,7 @@ func Packages(ctx *context.Context) {
Type: packages_model.Type(packageType),
Name: packages_model.SearchValue{Value: query},
Sort: sort,
- IsInternal: util.OptionalBoolFalse,
+ IsInternal: optional.Some(false),
Paginator: &db.ListOptions{
PageSize: setting.UI.PackagesPagingNum,
Page: page,
diff --git a/routers/web/admin/users.go b/routers/web/admin/users.go
index bbdbc820d7829..a34e0d0f0dc5b 100644
--- a/routers/web/admin/users.go
+++ b/routers/web/admin/users.go
@@ -96,7 +96,7 @@ func NewUser(ctx *context.Context) {
ctx.Data["login_type"] = "0-0"
sources, err := db.Find[auth.Source](ctx, auth.FindSourcesOptions{
- IsActive: util.OptionalBoolTrue,
+ IsActive: optional.Some(true),
})
if err != nil {
ctx.ServerError("auth.Sources", err)
@@ -117,7 +117,7 @@ func NewUserPost(ctx *context.Context) {
ctx.Data["AllowedUserVisibilityModes"] = setting.Service.AllowedUserVisibilityModesSlice.ToVisibleTypeSlice()
sources, err := db.Find[auth.Source](ctx, auth.FindSourcesOptions{
- IsActive: util.OptionalBoolTrue,
+ IsActive: optional.Some(true),
})
if err != nil {
ctx.ServerError("auth.Sources", err)
@@ -439,6 +439,7 @@ func EditUserPost(ctx *context.Context) {
AllowCreateOrganization: optional.Some(form.AllowCreateOrganization),
IsRestricted: optional.Some(form.Restricted),
Visibility: optional.Some(form.Visibility),
+ Language: optional.Some(form.Language),
}
if err := user_service.UpdateUser(ctx, u, opts); err != nil {
diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go
index 7704a110a67b5..04e410543d2ce 100644
--- a/routers/web/auth/auth.go
+++ b/routers/web/auth/auth.go
@@ -163,7 +163,7 @@ func SignIn(ctx *context.Context) {
return
}
- oauth2Providers, err := oauth2.GetOAuth2Providers(ctx, util.OptionalBoolTrue)
+ oauth2Providers, err := oauth2.GetOAuth2Providers(ctx, optional.Some(true))
if err != nil {
ctx.ServerError("UserSignIn", err)
return
@@ -186,7 +186,7 @@ func SignIn(ctx *context.Context) {
func SignInPost(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("sign_in")
- oauth2Providers, err := oauth2.GetOAuth2Providers(ctx, util.OptionalBoolTrue)
+ oauth2Providers, err := oauth2.GetOAuth2Providers(ctx, optional.Some(true))
if err != nil {
ctx.ServerError("UserSignIn", err)
return
@@ -410,7 +410,7 @@ func SignUp(ctx *context.Context) {
ctx.Data["SignUpLink"] = setting.AppSubURL + "/user/sign_up"
- oauth2Providers, err := oauth2.GetOAuth2Providers(ctx, util.OptionalBoolTrue)
+ oauth2Providers, err := oauth2.GetOAuth2Providers(ctx, optional.Some(true))
if err != nil {
ctx.ServerError("UserSignUp", err)
return
@@ -439,7 +439,7 @@ func SignUpPost(ctx *context.Context) {
ctx.Data["SignUpLink"] = setting.AppSubURL + "/user/sign_up"
- oauth2Providers, err := oauth2.GetOAuth2Providers(ctx, util.OptionalBoolTrue)
+ oauth2Providers, err := oauth2.GetOAuth2Providers(ctx, optional.Some(true))
if err != nil {
ctx.ServerError("UserSignUp", err)
return
diff --git a/routers/web/org/projects.go b/routers/web/org/projects.go
index 82cd91997a5a5..ad8bb90d9ea82 100644
--- a/routers/web/org/projects.go
+++ b/routers/web/org/projects.go
@@ -18,9 +18,9 @@ import (
"code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/json"
+ "code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/templates"
- "code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
shared_user "code.gitea.io/gitea/routers/web/shared/user"
"code.gitea.io/gitea/services/context"
@@ -67,7 +67,7 @@ func Projects(ctx *context.Context) {
PageSize: setting.UI.IssuePagingNum,
},
OwnerID: ctx.ContextUser.ID,
- IsClosed: util.OptionalBoolOf(isShowClosed),
+ IsClosed: optional.Some(isShowClosed),
OrderBy: project_model.GetSearchOrderByBySortType(sortType),
Type: projectType,
Title: keyword,
@@ -79,7 +79,7 @@ func Projects(ctx *context.Context) {
opTotal, err := db.Count[project_model.Project](ctx, project_model.SearchOptions{
OwnerID: ctx.ContextUser.ID,
- IsClosed: util.OptionalBoolOf(!isShowClosed),
+ IsClosed: optional.Some(!isShowClosed),
Type: projectType,
})
if err != nil {
@@ -388,7 +388,7 @@ func ViewProject(ctx *context.Context) {
if len(referencedIDs) > 0 {
if linkedPrs, err := issues_model.Issues(ctx, &issues_model.IssuesOptions{
IssueIDs: referencedIDs,
- IsPull: util.OptionalBoolTrue,
+ IsPull: optional.Some(true),
}); err == nil {
linkedPrsMap[issue.ID] = linkedPrs
}
diff --git a/routers/web/repo/actions/actions.go b/routers/web/repo/actions/actions.go
index e784912377936..f27329aa0f02c 100644
--- a/routers/web/repo/actions/actions.go
+++ b/routers/web/repo/actions/actions.go
@@ -16,8 +16,8 @@ import (
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/git"
+ "code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/routers/web/repo"
"code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/convert"
@@ -78,7 +78,7 @@ func List(ctx *context.Context) {
// Get all runner labels
runners, err := db.Find[actions_model.ActionRunner](ctx, actions_model.FindRunnerOptions{
RepoID: ctx.Repo.Repository.ID,
- IsOnline: util.OptionalBoolTrue,
+ IsOnline: optional.Some(true),
WithAvailable: true,
})
if err != nil {
diff --git a/routers/web/repo/actions/view.go b/routers/web/repo/actions/view.go
index 52c3cf1d07c19..3f8030e40d7b7 100644
--- a/routers/web/repo/actions/view.go
+++ b/routers/web/repo/actions/view.go
@@ -22,6 +22,7 @@ import (
"code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/modules/actions"
"code.gitea.io/gitea/modules/base"
+ "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/storage"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
@@ -602,6 +603,28 @@ func ArtifactsDownloadView(ctx *context_module.Context) {
ctx.Resp.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s.zip; filename*=UTF-8''%s.zip", url.PathEscape(artifactName), artifactName))
+ // Artifacts using the v4 backend are stored as a single combined zip file per artifact on the backend
+ // The v4 backend enshures ContentEncoding is set to "application/zip", which is not the case for the old backend
+ if len(artifacts) == 1 && artifacts[0].ArtifactName+".zip" == artifacts[0].ArtifactPath && artifacts[0].ContentEncoding == "application/zip" {
+ art := artifacts[0]
+ if setting.Actions.ArtifactStorage.MinioConfig.ServeDirect {
+ u, err := storage.ActionsArtifacts.URL(art.StoragePath, art.ArtifactPath)
+ if u != nil && err == nil {
+ ctx.Redirect(u.String())
+ return
+ }
+ }
+ f, err := storage.ActionsArtifacts.Open(art.StoragePath)
+ if err != nil {
+ ctx.Error(http.StatusInternalServerError, err.Error())
+ return
+ }
+ _, _ = io.Copy(ctx.Resp, f)
+ return
+ }
+
+ // Artifacts using the v1-v3 backend are stored as multiple individual files per artifact on the backend
+ // Those need to be zipped for download
writer := zip.NewWriter(ctx.Resp)
defer writer.Close()
for _, art := range artifacts {
diff --git a/routers/web/repo/branch.go b/routers/web/repo/branch.go
index 05f06a3ceb7a9..ae51f0596b2de 100644
--- a/routers/web/repo/branch.go
+++ b/routers/web/repo/branch.go
@@ -18,6 +18,7 @@ import (
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/optional"
repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
@@ -53,7 +54,7 @@ func Branches(ctx *context.Context) {
kw := ctx.FormString("q")
- defaultBranch, branches, branchesCount, err := repo_service.LoadBranches(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, util.OptionalBoolNone, kw, page, pageSize)
+ defaultBranch, branches, branchesCount, err := repo_service.LoadBranches(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, optional.None[bool](), kw, page, pageSize)
if err != nil {
ctx.ServerError("LoadBranches", err)
return
@@ -231,7 +232,7 @@ func CreateBranch(ctx *context.Context) {
if len(e.Message) == 0 {
ctx.Flash.Error(ctx.Tr("repo.editor.push_rejected_no_message"))
} else {
- flashError, err := ctx.RenderToString(tplAlertDetails, map[string]any{
+ flashError, err := ctx.RenderToHTML(tplAlertDetails, map[string]any{
"Message": ctx.Tr("repo.editor.push_rejected"),
"Summary": ctx.Tr("repo.editor.push_rejected_summary"),
"Details": utils.SanitizeFlashErrorString(e.Message),
diff --git a/routers/web/repo/editor.go b/routers/web/repo/editor.go
index 8f3d9612eca0b..6146ce4ce4a38 100644
--- a/routers/web/repo/editor.go
+++ b/routers/web/repo/editor.go
@@ -341,7 +341,7 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b
if len(errPushRej.Message) == 0 {
ctx.RenderWithErr(ctx.Tr("repo.editor.push_rejected_no_message"), tplEditFile, &form)
} else {
- flashError, err := ctx.RenderToString(tplAlertDetails, map[string]any{
+ flashError, err := ctx.RenderToHTML(tplAlertDetails, map[string]any{
"Message": ctx.Tr("repo.editor.push_rejected"),
"Summary": ctx.Tr("repo.editor.push_rejected_summary"),
"Details": utils.SanitizeFlashErrorString(errPushRej.Message),
@@ -353,7 +353,7 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b
ctx.RenderWithErr(flashError, tplEditFile, &form)
}
} else {
- flashError, err := ctx.RenderToString(tplAlertDetails, map[string]any{
+ flashError, err := ctx.RenderToHTML(tplAlertDetails, map[string]any{
"Message": ctx.Tr("repo.editor.fail_to_update_file", form.TreePath),
"Summary": ctx.Tr("repo.editor.fail_to_update_file_summary"),
"Details": utils.SanitizeFlashErrorString(err.Error()),
@@ -542,7 +542,7 @@ func DeleteFilePost(ctx *context.Context) {
if len(errPushRej.Message) == 0 {
ctx.RenderWithErr(ctx.Tr("repo.editor.push_rejected_no_message"), tplDeleteFile, &form)
} else {
- flashError, err := ctx.RenderToString(tplAlertDetails, map[string]any{
+ flashError, err := ctx.RenderToHTML(tplAlertDetails, map[string]any{
"Message": ctx.Tr("repo.editor.push_rejected"),
"Summary": ctx.Tr("repo.editor.push_rejected_summary"),
"Details": utils.SanitizeFlashErrorString(errPushRej.Message),
@@ -742,7 +742,7 @@ func UploadFilePost(ctx *context.Context) {
if len(errPushRej.Message) == 0 {
ctx.RenderWithErr(ctx.Tr("repo.editor.push_rejected_no_message"), tplUploadFile, &form)
} else {
- flashError, err := ctx.RenderToString(tplAlertDetails, map[string]any{
+ flashError, err := ctx.RenderToHTML(tplAlertDetails, map[string]any{
"Message": ctx.Tr("repo.editor.push_rejected"),
"Summary": ctx.Tr("repo.editor.push_rejected_summary"),
"Details": utils.SanitizeFlashErrorString(errPushRej.Message),
diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go
index ebaa955ac8057..1abd5e2ba5a3d 100644
--- a/routers/web/repo/issue.go
+++ b/routers/web/repo/issue.go
@@ -9,6 +9,7 @@ import (
stdCtx "context"
"errors"
"fmt"
+ "html/template"
"math/big"
"net/http"
"net/url"
@@ -139,7 +140,7 @@ func MustAllowPulls(ctx *context.Context) {
}
}
-func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption util.OptionalBool) {
+func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption optional.Option[bool]) {
var err error
viewType := ctx.FormString("type")
sortType := ctx.FormString("sort")
@@ -240,18 +241,18 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
}
}
- var isShowClosed util.OptionalBool
+ var isShowClosed optional.Option[bool]
switch ctx.FormString("state") {
case "closed":
- isShowClosed = util.OptionalBoolTrue
+ isShowClosed = optional.Some(true)
case "all":
- isShowClosed = util.OptionalBoolNone
+ isShowClosed = optional.None[bool]()
default:
- isShowClosed = util.OptionalBoolFalse
+ isShowClosed = optional.Some(false)
}
// if there are closed issues and no open issues, default to showing all issues
if len(ctx.FormString("state")) == 0 && issueStats.OpenCount == 0 && issueStats.ClosedCount != 0 {
- isShowClosed = util.OptionalBoolNone
+ isShowClosed = optional.None[bool]()
}
if repo.IsTimetrackerEnabled(ctx) {
@@ -271,10 +272,10 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
}
var total int
- switch isShowClosed {
- case util.OptionalBoolTrue:
+ switch {
+ case isShowClosed.Value():
total = int(issueStats.ClosedCount)
- case util.OptionalBoolNone:
+ case !isShowClosed.Has():
total = int(issueStats.OpenCount + issueStats.ClosedCount)
default:
total = int(issueStats.OpenCount)
@@ -430,7 +431,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
return
}
- pinned, err := issues_model.GetPinnedIssues(ctx, repo.ID, isPullOption.IsTrue())
+ pinned, err := issues_model.GetPinnedIssues(ctx, repo.ID, isPullOption.Value())
if err != nil {
ctx.ServerError("GetPinnedIssues", err)
return
@@ -460,10 +461,10 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
ctx.Data["AssigneeID"] = assigneeID
ctx.Data["PosterID"] = posterID
ctx.Data["Keyword"] = keyword
- switch isShowClosed {
- case util.OptionalBoolTrue:
+ switch {
+ case isShowClosed.Value():
ctx.Data["State"] = "closed"
- case util.OptionalBoolNone:
+ case !isShowClosed.Has():
ctx.Data["State"] = "all"
default:
ctx.Data["State"] = "open"
@@ -512,7 +513,7 @@ func Issues(ctx *context.Context) {
ctx.Data["NewIssueChooseTemplate"] = issue_service.HasTemplatesOrContactLinks(ctx.Repo.Repository, ctx.Repo.GitRepo)
}
- issues(ctx, ctx.FormInt64("milestone"), ctx.FormInt64("project"), util.OptionalBoolOf(isPullList))
+ issues(ctx, ctx.FormInt64("milestone"), ctx.FormInt64("project"), optional.Some(isPullList))
if ctx.Written() {
return
}
@@ -554,7 +555,7 @@ func RetrieveRepoMilestonesAndAssignees(ctx *context.Context, repo *repo_model.R
var err error
ctx.Data["OpenMilestones"], err = db.Find[issues_model.Milestone](ctx, issues_model.FindMilestoneOptions{
RepoID: repo.ID,
- IsClosed: util.OptionalBoolFalse,
+ IsClosed: optional.Some(false),
})
if err != nil {
ctx.ServerError("GetMilestones", err)
@@ -562,7 +563,7 @@ func RetrieveRepoMilestonesAndAssignees(ctx *context.Context, repo *repo_model.R
}
ctx.Data["ClosedMilestones"], err = db.Find[issues_model.Milestone](ctx, issues_model.FindMilestoneOptions{
RepoID: repo.ID,
- IsClosed: util.OptionalBoolTrue,
+ IsClosed: optional.Some(true),
})
if err != nil {
ctx.ServerError("GetMilestones", err)
@@ -590,7 +591,7 @@ func retrieveProjects(ctx *context.Context, repo *repo_model.Repository) {
projects, err := db.Find[project_model.Project](ctx, project_model.SearchOptions{
ListOptions: db.ListOptionsAll,
RepoID: repo.ID,
- IsClosed: util.OptionalBoolFalse,
+ IsClosed: optional.Some(false),
Type: project_model.TypeRepository,
})
if err != nil {
@@ -600,7 +601,7 @@ func retrieveProjects(ctx *context.Context, repo *repo_model.Repository) {
projects2, err := db.Find[project_model.Project](ctx, project_model.SearchOptions{
ListOptions: db.ListOptionsAll,
OwnerID: repo.OwnerID,
- IsClosed: util.OptionalBoolFalse,
+ IsClosed: optional.Some(false),
Type: repoOwnerType,
})
if err != nil {
@@ -613,7 +614,7 @@ func retrieveProjects(ctx *context.Context, repo *repo_model.Repository) {
projects, err = db.Find[project_model.Project](ctx, project_model.SearchOptions{
ListOptions: db.ListOptionsAll,
RepoID: repo.ID,
- IsClosed: util.OptionalBoolTrue,
+ IsClosed: optional.Some(true),
Type: project_model.TypeRepository,
})
if err != nil {
@@ -623,7 +624,7 @@ func retrieveProjects(ctx *context.Context, repo *repo_model.Repository) {
projects2, err = db.Find[project_model.Project](ctx, project_model.SearchOptions{
ListOptions: db.ListOptionsAll,
OwnerID: repo.OwnerID,
- IsClosed: util.OptionalBoolTrue,
+ IsClosed: optional.Some(true),
Type: repoOwnerType,
})
if err != nil {
@@ -1016,7 +1017,7 @@ func NewIssue(ctx *context.Context) {
ctx.HTML(http.StatusOK, tplIssueNew)
}
-func renderErrorOfTemplates(ctx *context.Context, errs map[string]error) string {
+func renderErrorOfTemplates(ctx *context.Context, errs map[string]error) template.HTML {
var files []string
for k := range errs {
files = append(files, k)
@@ -1028,14 +1029,14 @@ func renderErrorOfTemplates(ctx *context.Context, errs map[string]error) string
lines = append(lines, fmt.Sprintf("%s: %v", file, errs[file]))
}
- flashError, err := ctx.RenderToString(tplAlertDetails, map[string]any{
+ flashError, err := ctx.RenderToHTML(tplAlertDetails, map[string]any{
"Message": ctx.Tr("repo.issues.choose.ignore_invalid_templates"),
"Summary": ctx.Tr("repo.issues.choose.invalid_templates", len(errs)),
"Details": utils.SanitizeFlashErrorString(strings.Join(lines, "\n")),
})
if err != nil {
log.Debug("render flash error: %v", err)
- flashError = ctx.Locale.TrString("repo.issues.choose.ignore_invalid_templates")
+ flashError = ctx.Locale.Tr("repo.issues.choose.ignore_invalid_templates")
}
return flashError
}
@@ -2501,14 +2502,14 @@ func SearchIssues(ctx *context.Context) {
return
}
- var isClosed util.OptionalBool
+ var isClosed optional.Option[bool]
switch ctx.FormString("state") {
case "closed":
- isClosed = util.OptionalBoolTrue
+ isClosed = optional.Some(true)
case "all":
- isClosed = util.OptionalBoolNone
+ isClosed = optional.None[bool]()
default:
- isClosed = util.OptionalBoolFalse
+ isClosed = optional.Some(false)
}
var (
@@ -2583,14 +2584,12 @@ func SearchIssues(ctx *context.Context) {
keyword = ""
}
- var isPull util.OptionalBool
+ isPull := optional.None[bool]()
switch ctx.FormString("type") {
case "pulls":
- isPull = util.OptionalBoolTrue
+ isPull = optional.Some(true)
case "issues":
- isPull = util.OptionalBoolFalse
- default:
- isPull = util.OptionalBoolNone
+ isPull = optional.Some(false)
}
var includedAnyLabels []int64
@@ -2725,14 +2724,14 @@ func ListIssues(ctx *context.Context) {
return
}
- var isClosed util.OptionalBool
+ var isClosed optional.Option[bool]
switch ctx.FormString("state") {
case "closed":
- isClosed = util.OptionalBoolTrue
+ isClosed = optional.Some(true)
case "all":
- isClosed = util.OptionalBoolNone
+ isClosed = optional.None[bool]()
default:
- isClosed = util.OptionalBoolFalse
+ isClosed = optional.Some(false)
}
keyword := ctx.FormTrim("q")
@@ -2784,14 +2783,12 @@ func ListIssues(ctx *context.Context) {
projectID = &v
}
- var isPull util.OptionalBool
+ isPull := optional.None[bool]()
switch ctx.FormString("type") {
case "pulls":
- isPull = util.OptionalBoolTrue
+ isPull = optional.Some(true)
case "issues":
- isPull = util.OptionalBoolFalse
- default:
- isPull = util.OptionalBoolNone
+ isPull = optional.Some(false)
}
// FIXME: we should be more efficient here
@@ -3296,7 +3293,7 @@ func ChangeIssueReaction(ctx *context.Context) {
return
}
- html, err := ctx.RenderToString(tplReactions, map[string]any{
+ html, err := ctx.RenderToHTML(tplReactions, map[string]any{
"ctxData": ctx.Data,
"ActionURL": fmt.Sprintf("%s/issues/%d/reactions", ctx.Repo.RepoLink, issue.Index),
"Reactions": issue.Reactions.GroupByType(),
@@ -3403,7 +3400,7 @@ func ChangeCommentReaction(ctx *context.Context) {
return
}
- html, err := ctx.RenderToString(tplReactions, map[string]any{
+ html, err := ctx.RenderToHTML(tplReactions, map[string]any{
"ctxData": ctx.Data,
"ActionURL": fmt.Sprintf("%s/comments/%d/reactions", ctx.Repo.RepoLink, comment.ID),
"Reactions": comment.Reactions.GroupByType(),
@@ -3546,8 +3543,8 @@ func updateAttachments(ctx *context.Context, item any, files []string) error {
return err
}
-func attachmentsHTML(ctx *context.Context, attachments []*repo_model.Attachment, content string) string {
- attachHTML, err := ctx.RenderToString(tplAttachment, map[string]any{
+func attachmentsHTML(ctx *context.Context, attachments []*repo_model.Attachment, content string) template.HTML {
+ attachHTML, err := ctx.RenderToHTML(tplAttachment, map[string]any{
"ctxData": ctx.Data,
"Attachments": attachments,
"Content": content,
diff --git a/routers/web/repo/milestone.go b/routers/web/repo/milestone.go
index 49ac94aaf1540..c41b844ce4de8 100644
--- a/routers/web/repo/milestone.go
+++ b/routers/web/repo/milestone.go
@@ -14,9 +14,9 @@ import (
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/markup/markdown"
+ "code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
- "code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/forms"
@@ -51,7 +51,7 @@ func Milestones(ctx *context.Context) {
PageSize: setting.UI.IssuePagingNum,
},
RepoID: ctx.Repo.Repository.ID,
- IsClosed: util.OptionalBoolOf(isShowClosed),
+ IsClosed: optional.Some(isShowClosed),
SortType: sortType,
Name: keyword,
})
@@ -292,7 +292,7 @@ func MilestoneIssuesAndPulls(ctx *context.Context) {
ctx.Data["Title"] = milestone.Name
ctx.Data["Milestone"] = milestone
- issues(ctx, milestoneID, projectID, util.OptionalBoolNone)
+ issues(ctx, milestoneID, projectID, optional.None[bool]())
ret := issue.ParseTemplatesFromDefaultBranch(ctx.Repo.Repository, ctx.Repo.GitRepo)
ctx.Data["NewIssueChooseTemplate"] = len(ret.IssueTemplates) > 0
diff --git a/routers/web/repo/packages.go b/routers/web/repo/packages.go
index 6ed5909dcf6bf..11874ab0d04a6 100644
--- a/routers/web/repo/packages.go
+++ b/routers/web/repo/packages.go
@@ -10,8 +10,8 @@ import (
"code.gitea.io/gitea/models/packages"
"code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/modules/base"
+ "code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/context"
)
@@ -37,7 +37,7 @@ func Packages(ctx *context.Context) {
RepoID: ctx.Repo.Repository.ID,
Type: packages.Type(packageType),
Name: packages.SearchValue{Value: query},
- IsInternal: util.OptionalBoolFalse,
+ IsInternal: optional.Some(false),
})
if err != nil {
ctx.ServerError("SearchLatestVersions", err)
diff --git a/routers/web/repo/projects.go b/routers/web/repo/projects.go
index 1f9ee727c362e..4c171defbd4ff 100644
--- a/routers/web/repo/projects.go
+++ b/routers/web/repo/projects.go
@@ -20,8 +20,8 @@ import (
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/markup/markdown"
+ "code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/forms"
@@ -78,7 +78,7 @@ func Projects(ctx *context.Context) {
Page: page,
},
RepoID: repo.ID,
- IsClosed: util.OptionalBoolOf(isShowClosed),
+ IsClosed: optional.Some(isShowClosed),
OrderBy: project_model.GetSearchOrderByBySortType(sortType),
Type: project_model.TypeRepository,
Title: keyword,
@@ -349,7 +349,7 @@ func ViewProject(ctx *context.Context) {
if len(referencedIDs) > 0 {
if linkedPrs, err := issues_model.Issues(ctx, &issues_model.IssuesOptions{
IssueIDs: referencedIDs,
- IsPull: util.OptionalBoolTrue,
+ IsPull: optional.Some(true),
}); err == nil {
linkedPrsMap[issue.ID] = linkedPrs
}
diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go
index c97edd8720ed0..bf52d76e95616 100644
--- a/routers/web/repo/pull.go
+++ b/routers/web/repo/pull.go
@@ -1129,7 +1129,7 @@ func UpdatePullRequest(ctx *context.Context) {
if err = pull_service.Update(ctx, issue.PullRequest, ctx.Doer, message, rebase); err != nil {
if models.IsErrMergeConflicts(err) {
conflictError := err.(models.ErrMergeConflicts)
- flashError, err := ctx.RenderToString(tplAlertDetails, map[string]any{
+ flashError, err := ctx.RenderToHTML(tplAlertDetails, map[string]any{
"Message": ctx.Tr("repo.pulls.merge_conflict"),
"Summary": ctx.Tr("repo.pulls.merge_conflict_summary"),
"Details": utils.SanitizeFlashErrorString(conflictError.StdErr) + "
" + utils.SanitizeFlashErrorString(conflictError.StdOut),
@@ -1143,7 +1143,7 @@ func UpdatePullRequest(ctx *context.Context) {
return
} else if models.IsErrRebaseConflicts(err) {
conflictError := err.(models.ErrRebaseConflicts)
- flashError, err := ctx.RenderToString(tplAlertDetails, map[string]any{
+ flashError, err := ctx.RenderToHTML(tplAlertDetails, map[string]any{
"Message": ctx.Tr("repo.pulls.rebase_conflict", utils.SanitizeFlashErrorString(conflictError.CommitSHA)),
"Summary": ctx.Tr("repo.pulls.rebase_conflict_summary"),
"Details": utils.SanitizeFlashErrorString(conflictError.StdErr) + "
" + utils.SanitizeFlashErrorString(conflictError.StdOut),
@@ -1275,7 +1275,7 @@ func MergePullRequest(ctx *context.Context) {
ctx.JSONError(ctx.Tr("repo.pulls.invalid_merge_option"))
} else if models.IsErrMergeConflicts(err) {
conflictError := err.(models.ErrMergeConflicts)
- flashError, err := ctx.RenderToString(tplAlertDetails, map[string]any{
+ flashError, err := ctx.RenderToHTML(tplAlertDetails, map[string]any{
"Message": ctx.Tr("repo.editor.merge_conflict"),
"Summary": ctx.Tr("repo.editor.merge_conflict_summary"),
"Details": utils.SanitizeFlashErrorString(conflictError.StdErr) + "
" + utils.SanitizeFlashErrorString(conflictError.StdOut),
@@ -1288,7 +1288,7 @@ func MergePullRequest(ctx *context.Context) {
ctx.JSONRedirect(issue.Link())
} else if models.IsErrRebaseConflicts(err) {
conflictError := err.(models.ErrRebaseConflicts)
- flashError, err := ctx.RenderToString(tplAlertDetails, map[string]any{
+ flashError, err := ctx.RenderToHTML(tplAlertDetails, map[string]any{
"Message": ctx.Tr("repo.pulls.rebase_conflict", utils.SanitizeFlashErrorString(conflictError.CommitSHA)),
"Summary": ctx.Tr("repo.pulls.rebase_conflict_summary"),
"Details": utils.SanitizeFlashErrorString(conflictError.StdErr) + "
" + utils.SanitizeFlashErrorString(conflictError.StdOut),
@@ -1318,7 +1318,7 @@ func MergePullRequest(ctx *context.Context) {
if len(message) == 0 {
ctx.Flash.Error(ctx.Tr("repo.pulls.push_rejected_no_message"))
} else {
- flashError, err := ctx.RenderToString(tplAlertDetails, map[string]any{
+ flashError, err := ctx.RenderToHTML(tplAlertDetails, map[string]any{
"Message": ctx.Tr("repo.pulls.push_rejected"),
"Summary": ctx.Tr("repo.pulls.push_rejected_summary"),
"Details": utils.SanitizeFlashErrorString(pushrejErr.Message),
@@ -1491,7 +1491,7 @@ func CompareAndPullRequestPost(ctx *context.Context) {
ctx.JSONError(ctx.Tr("repo.pulls.push_rejected_no_message"))
return
}
- flashError, err := ctx.RenderToString(tplAlertDetails, map[string]any{
+ flashError, err := ctx.RenderToHTML(tplAlertDetails, map[string]any{
"Message": ctx.Tr("repo.pulls.push_rejected"),
"Summary": ctx.Tr("repo.pulls.push_rejected_summary"),
"Details": utils.SanitizeFlashErrorString(pushrejErr.Message),
@@ -1500,8 +1500,7 @@ func CompareAndPullRequestPost(ctx *context.Context) {
ctx.ServerError("CompareAndPullRequest.HTMLString", err)
return
}
- ctx.Flash.Error(flashError)
- ctx.JSONRedirect(pullIssue.Link()) // FIXME: it's unfriendly, and will make the content lost
+ ctx.JSONError(flashError)
return
}
ctx.ServerError("NewPullRequest", err)
diff --git a/routers/web/repo/release.go b/routers/web/repo/release.go
index c6d8c45af10f1..dbc190928f946 100644
--- a/routers/web/repo/release.go
+++ b/routers/web/repo/release.go
@@ -185,6 +185,11 @@ func Releases(ctx *context.Context) {
ctx.ServerError("getReleaseInfos", err)
return
}
+ for _, rel := range releases {
+ if rel.Release.IsTag && rel.Release.Title == "" {
+ rel.Release.Title = rel.Release.TagName
+ }
+ }
ctx.Data["Releases"] = releases
@@ -283,6 +288,7 @@ func SingleRelease(ctx *context.Context) {
TagNames: []string{ctx.Params("*")},
// only show draft releases for users who can write, read-only users shouldn't see draft releases.
IncludeDrafts: writeAccess,
+ IncludeTags: true,
})
if err != nil {
ctx.ServerError("getReleaseInfos", err)
@@ -294,6 +300,9 @@ func SingleRelease(ctx *context.Context) {
}
release := releases[0].Release
+ if release.IsTag && release.Title == "" {
+ release.Title = release.TagName
+ }
ctx.Data["PageIsSingleTag"] = release.IsTag
if release.IsTag {
diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go
index e89739e2fb6d1..4df10fbea1adb 100644
--- a/routers/web/repo/view.go
+++ b/routers/web/repo/view.go
@@ -35,7 +35,6 @@ import (
"code.gitea.io/gitea/modules/actions"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/charset"
- "code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/highlight"
"code.gitea.io/gitea/modules/lfs"
@@ -859,25 +858,18 @@ func renderDirectoryFiles(ctx *context.Context, timeout time.Duration) git.Entri
defer cancel()
}
- selected := make(container.Set[string])
- selected.AddMultiple(ctx.FormStrings("f[]")...)
-
- entries := allEntries
- if len(selected) > 0 {
- entries = make(git.Entries, 0, len(selected))
- for _, entry := range allEntries {
- if selected.Contains(entry.Name()) {
- entries = append(entries, entry)
- }
- }
- }
-
- var latestCommit *git.Commit
- ctx.Data["Files"], latestCommit, err = entries.GetCommitsInfo(commitInfoCtx, ctx.Repo.Commit, ctx.Repo.TreePath)
+ files, latestCommit, err := allEntries.GetCommitsInfo(commitInfoCtx, ctx.Repo.Commit, ctx.Repo.TreePath)
if err != nil {
ctx.ServerError("GetCommitsInfo", err)
return nil
}
+ ctx.Data["Files"] = files
+ for _, f := range files {
+ if f.Commit == nil {
+ ctx.Data["HasFilesWithoutLatestCommit"] = true
+ break
+ }
+ }
if !loadLatestCommitData(ctx, latestCommit) {
return nil
diff --git a/routers/web/shared/packages/packages.go b/routers/web/shared/packages/packages.go
index 1454396f041da..57671ad8f14bc 100644
--- a/routers/web/shared/packages/packages.go
+++ b/routers/web/shared/packages/packages.go
@@ -13,7 +13,7 @@ import (
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/log"
- "code.gitea.io/gitea/modules/util"
+ "code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/forms"
@@ -157,7 +157,7 @@ func SetRulePreviewContext(ctx *context.Context, owner *user_model.User) {
for _, p := range packages {
pvs, _, err := packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{
PackageID: p.ID,
- IsInternal: util.OptionalBoolFalse,
+ IsInternal: optional.Some(false),
Sort: packages_model.SortCreatedDesc,
Paginator: db.NewAbsoluteListOptions(pcr.KeepCount, 200),
})
diff --git a/routers/web/shared/user/header.go b/routers/web/shared/user/header.go
index 51b04e0613a58..3bc1adae99ec6 100644
--- a/routers/web/shared/user/header.go
+++ b/routers/web/shared/user/header.go
@@ -18,7 +18,6 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/context"
)
@@ -131,7 +130,7 @@ func LoadHeaderCount(ctx *context.Context) error {
}
projectCount, err := db.Count[project_model.Project](ctx, project_model.SearchOptions{
OwnerID: ctx.ContextUser.ID,
- IsClosed: util.OptionalBoolOf(false),
+ IsClosed: optional.Some(false),
Type: projectType,
})
if err != nil {
diff --git a/routers/web/user/home.go b/routers/web/user/home.go
index 6f36806ff7554..caa71152593ef 100644
--- a/routers/web/user/home.go
+++ b/routers/web/user/home.go
@@ -30,7 +30,6 @@ import (
"code.gitea.io/gitea/modules/markup/markdown"
"code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/routers/web/feed"
"code.gitea.io/gitea/services/context"
issue_service "code.gitea.io/gitea/services/issue"
@@ -215,7 +214,7 @@ func Milestones(ctx *context.Context) {
counts, err := issues_model.CountMilestonesMap(ctx, issues_model.FindMilestoneOptions{
RepoCond: userRepoCond,
Name: keyword,
- IsClosed: util.OptionalBoolOf(isShowClosed),
+ IsClosed: optional.Some(isShowClosed),
})
if err != nil {
ctx.ServerError("CountMilestonesByRepoIDs", err)
@@ -228,7 +227,7 @@ func Milestones(ctx *context.Context) {
PageSize: setting.UI.IssuePagingNum,
},
RepoCond: repoCond,
- IsClosed: util.OptionalBoolOf(isShowClosed),
+ IsClosed: optional.Some(isShowClosed),
SortType: sortType,
Name: keyword,
})
@@ -440,9 +439,9 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
isPullList := unitType == unit.TypePullRequests
opts := &issues_model.IssuesOptions{
- IsPull: util.OptionalBoolOf(isPullList),
+ IsPull: optional.Some(isPullList),
SortType: sortType,
- IsArchived: util.OptionalBoolFalse,
+ IsArchived: optional.Some(false),
Org: org,
Team: team,
User: ctx.Doer,
@@ -516,7 +515,7 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
// Educated guess: Do or don't show closed issues.
isShowClosed := ctx.FormString("state") == "closed"
- opts.IsClosed = util.OptionalBoolOf(isShowClosed)
+ opts.IsClosed = optional.Some(isShowClosed)
// Make sure page number is at least 1. Will be posted to ctx.Data.
page := ctx.FormInt("page")
@@ -800,12 +799,12 @@ func getUserIssueStats(ctx *context.Context, ctxUser *user_model.User, filterMod
case issues_model.FilterModeReviewed:
openClosedOpts.ReviewedID = &doerID
}
- openClosedOpts.IsClosed = util.OptionalBoolFalse
+ openClosedOpts.IsClosed = optional.Some(false)
ret.OpenCount, err = issue_indexer.CountIssues(ctx, openClosedOpts)
if err != nil {
return nil, err
}
- openClosedOpts.IsClosed = util.OptionalBoolTrue
+ openClosedOpts.IsClosed = optional.Some(true)
ret.ClosedCount, err = issue_indexer.CountIssues(ctx, openClosedOpts)
if err != nil {
return nil, err
diff --git a/routers/web/user/notification.go b/routers/web/user/notification.go
index 801e1cf95eaf4..09e592d63a941 100644
--- a/routers/web/user/notification.go
+++ b/routers/web/user/notification.go
@@ -233,26 +233,25 @@ func NotificationSubscriptions(ctx *context.Context) {
if !util.SliceContainsString([]string{"all", "open", "closed"}, state, true) {
state = "all"
}
+
ctx.Data["State"] = state
- var showClosed util.OptionalBool
+ // default state filter is "all"
+ showClosed := optional.None[bool]()
switch state {
- case "all":
- showClosed = util.OptionalBoolNone
case "closed":
- showClosed = util.OptionalBoolTrue
+ showClosed = optional.Some(true)
case "open":
- showClosed = util.OptionalBoolFalse
+ showClosed = optional.Some(false)
}
- var issueTypeBool util.OptionalBool
issueType := ctx.FormString("issueType")
+ // default issue type is no filter
+ issueTypeBool := optional.None[bool]()
switch issueType {
case "issues":
- issueTypeBool = util.OptionalBoolFalse
+ issueTypeBool = optional.Some(false)
case "pulls":
- issueTypeBool = util.OptionalBoolTrue
- default:
- issueTypeBool = util.OptionalBoolNone
+ issueTypeBool = optional.Some(true)
}
ctx.Data["IssueType"] = issueType
diff --git a/routers/web/user/package.go b/routers/web/user/package.go
index d03b28309fd8f..3ecc59a2abad3 100644
--- a/routers/web/user/package.go
+++ b/routers/web/user/package.go
@@ -16,6 +16,7 @@ import (
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/optional"
alpine_module "code.gitea.io/gitea/modules/packages/alpine"
debian_module "code.gitea.io/gitea/modules/packages/debian"
rpm_module "code.gitea.io/gitea/modules/packages/rpm"
@@ -54,7 +55,7 @@ func ListPackages(ctx *context.Context) {
OwnerID: ctx.ContextUser.ID,
Type: packages_model.Type(packageType),
Name: packages_model.SearchValue{Value: query},
- IsInternal: util.OptionalBoolFalse,
+ IsInternal: optional.Some(false),
})
if err != nil {
ctx.ServerError("SearchLatestVersions", err)
@@ -145,7 +146,7 @@ func RedirectToLastVersion(ctx *context.Context) {
pvs, _, err := packages_model.SearchLatestVersions(ctx, &packages_model.PackageSearchOptions{
PackageID: p.ID,
- IsInternal: util.OptionalBoolFalse,
+ IsInternal: optional.Some(false),
})
if err != nil {
ctx.ServerError("GetPackageByName", err)
@@ -162,7 +163,7 @@ func RedirectToLastVersion(ctx *context.Context) {
return
}
- ctx.Redirect(pd.FullWebLink())
+ ctx.Redirect(pd.VersionWebLink())
}
// ViewPackageVersion displays a single package version
@@ -255,7 +256,7 @@ func ViewPackageVersion(ctx *context.Context) {
pvs, total, err = packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{
Paginator: db.NewAbsoluteListOptions(0, 5),
PackageID: pd.Package.ID,
- IsInternal: util.OptionalBoolFalse,
+ IsInternal: optional.Some(false),
})
}
if err != nil {
@@ -359,7 +360,7 @@ func ListPackageVersions(ctx *context.Context) {
ExactMatch: false,
Value: query,
},
- IsInternal: util.OptionalBoolFalse,
+ IsInternal: optional.Some(false),
Sort: sort,
})
if err != nil {
@@ -467,7 +468,7 @@ func PackageSettingsPost(ctx *context.Context) {
redirectURL := ctx.Package.Owner.HomeLink() + "/-/packages"
// redirect to the package if there are still versions available
- if has, _ := packages_model.ExistVersion(ctx, &packages_model.PackageSearchOptions{PackageID: ctx.Package.Descriptor.Package.ID, IsInternal: util.OptionalBoolFalse}); has {
+ if has, _ := packages_model.ExistVersion(ctx, &packages_model.PackageSearchOptions{PackageID: ctx.Package.Descriptor.Package.ID, IsInternal: optional.Some(false)}); has {
redirectURL = ctx.Package.Descriptor.PackageWebLink()
}
diff --git a/routers/web/user/setting/security/security.go b/routers/web/user/setting/security/security.go
index 30611dd9f19c8..8d6859ab87da9 100644
--- a/routers/web/user/setting/security/security.go
+++ b/routers/web/user/setting/security/security.go
@@ -12,8 +12,8 @@ import (
"code.gitea.io/gitea/models/db"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base"
+ "code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/auth/source/oauth2"
"code.gitea.io/gitea/services/context"
)
@@ -112,7 +112,7 @@ func loadSecurityData(ctx *context.Context) {
ctx.Data["AccountLinks"] = sources
authSources, err := db.Find[auth_model.Source](ctx, auth_model.FindSourcesOptions{
- IsActive: util.OptionalBoolNone,
+ IsActive: optional.None[bool](),
LoginType: auth_model.OAuth2,
})
if err != nil {
diff --git a/services/attachment/attachment.go b/services/attachment/attachment.go
index eab3d0b142a1b..0fd51e4fa5eeb 100644
--- a/services/attachment/attachment.go
+++ b/services/attachment/attachment.go
@@ -39,14 +39,14 @@ func NewAttachment(ctx context.Context, attach *repo_model.Attachment, file io.R
}
// UploadAttachment upload new attachment into storage and update database
-func UploadAttachment(ctx context.Context, file io.Reader, allowedTypes string, fileSize int64, opts *repo_model.Attachment) (*repo_model.Attachment, error) {
+func UploadAttachment(ctx context.Context, file io.Reader, allowedTypes string, fileSize int64, attach *repo_model.Attachment) (*repo_model.Attachment, error) {
buf := make([]byte, 1024)
n, _ := util.ReadAtMost(file, buf)
buf = buf[:n]
- if err := upload.Verify(buf, opts.Name, allowedTypes); err != nil {
+ if err := upload.Verify(buf, attach.Name, allowedTypes); err != nil {
return nil, err
}
- return NewAttachment(ctx, opts, io.MultiReader(bytes.NewReader(buf), file), fileSize)
+ return NewAttachment(ctx, attach, io.MultiReader(bytes.NewReader(buf), file), fileSize)
}
diff --git a/services/auth/signin.go b/services/auth/signin.go
index fafe3ef3c67b1..e116a088e09b0 100644
--- a/services/auth/signin.go
+++ b/services/auth/signin.go
@@ -11,7 +11,7 @@ import (
"code.gitea.io/gitea/models/db"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
- "code.gitea.io/gitea/modules/util"
+ "code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/services/auth/source/oauth2"
"code.gitea.io/gitea/services/auth/source/smtp"
@@ -87,7 +87,7 @@ func UserSignIn(ctx context.Context, username, password string) (*user_model.Use
}
sources, err := db.Find[auth.Source](ctx, auth.FindSourcesOptions{
- IsActive: util.OptionalBoolTrue,
+ IsActive: optional.Some(true),
})
if err != nil {
return nil, nil, err
diff --git a/services/auth/source/oauth2/init.go b/services/auth/source/oauth2/init.go
index 3ad6e307f106c..5c2568154863c 100644
--- a/services/auth/source/oauth2/init.go
+++ b/services/auth/source/oauth2/init.go
@@ -12,8 +12,8 @@ import (
"code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/modules/util"
"github.com/google/uuid"
"github.com/gorilla/sessions"
@@ -66,7 +66,7 @@ func ResetOAuth2(ctx context.Context) error {
// initOAuth2Sources is used to load and register all active OAuth2 providers
func initOAuth2Sources(ctx context.Context) error {
authSources, err := db.Find[auth.Source](ctx, auth.FindSourcesOptions{
- IsActive: util.OptionalBoolTrue,
+ IsActive: optional.Some(true),
LoginType: auth.OAuth2,
})
if err != nil {
diff --git a/services/auth/source/oauth2/providers.go b/services/auth/source/oauth2/providers.go
index f4edb507f2774..ac32647839b36 100644
--- a/services/auth/source/oauth2/providers.go
+++ b/services/auth/source/oauth2/providers.go
@@ -15,8 +15,8 @@ import (
"code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/modules/util"
"github.com/markbates/goth"
)
@@ -107,7 +107,7 @@ func CreateProviderFromSource(source *auth.Source) (Provider, error) {
}
// GetOAuth2Providers returns the list of configured OAuth2 providers
-func GetOAuth2Providers(ctx context.Context, isActive util.OptionalBool) ([]Provider, error) {
+func GetOAuth2Providers(ctx context.Context, isActive optional.Option[bool]) ([]Provider, error) {
authSources, err := db.Find[auth.Source](ctx, auth.FindSourcesOptions{
IsActive: isActive,
LoginType: auth.OAuth2,
diff --git a/services/auth/sspi.go b/services/auth/sspi.go
index 9108a0a668a42..64a127e97a6c3 100644
--- a/services/auth/sspi.go
+++ b/services/auth/sspi.go
@@ -17,7 +17,6 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web/middleware"
"code.gitea.io/gitea/services/auth/source/sspi"
gitea_context "code.gitea.io/gitea/services/context"
@@ -132,7 +131,7 @@ func (s *SSPI) Verify(req *http.Request, w http.ResponseWriter, store DataStore,
// getConfig retrieves the SSPI configuration from login sources
func (s *SSPI) getConfig(ctx context.Context) (*sspi.Source, error) {
sources, err := db.Find[auth.Source](ctx, auth.FindSourcesOptions{
- IsActive: util.OptionalBoolTrue,
+ IsActive: optional.Some(true),
LoginType: auth.SSPI,
})
if err != nil {
diff --git a/services/context/context_response.go b/services/context/context_response.go
index 829bca1f59209..372b4cb38b6f6 100644
--- a/services/context/context_response.go
+++ b/services/context/context_response.go
@@ -6,6 +6,7 @@ package context
import (
"errors"
"fmt"
+ "html/template"
"net"
"net/http"
"net/url"
@@ -104,11 +105,11 @@ func (ctx *Context) JSONTemplate(tmpl base.TplName) {
}
}
-// RenderToString renders the template content to a string
-func (ctx *Context) RenderToString(name base.TplName, data map[string]any) (string, error) {
+// RenderToHTML renders the template content to a HTML string
+func (ctx *Context) RenderToHTML(name base.TplName, data map[string]any) (template.HTML, error) {
var buf strings.Builder
- err := ctx.Render.HTML(&buf, http.StatusOK, string(name), data, ctx.TemplateContext)
- return buf.String(), err
+ err := ctx.Render.HTML(&buf, 0, string(name), data, ctx.TemplateContext)
+ return template.HTML(buf.String()), err
}
// RenderWithErr used for page has form validation but need to prompt error to users.
diff --git a/services/convert/package.go b/services/convert/package.go
index e90ce8a00f848..b5fca21a3c3a5 100644
--- a/services/convert/package.go
+++ b/services/convert/package.go
@@ -35,7 +35,7 @@ func ToPackage(ctx context.Context, pd *packages.PackageDescriptor, doer *user_m
Name: pd.Package.Name,
Version: pd.Version.Version,
CreatedAt: pd.Version.CreatedUnix.AsTime(),
- HTMLURL: pd.FullWebLink(),
+ HTMLURL: pd.VersionHTMLURL(),
}, nil
}
diff --git a/services/forms/admin.go b/services/forms/admin.go
index f112013060708..81276f8f46f9c 100644
--- a/services/forms/admin.go
+++ b/services/forms/admin.go
@@ -41,6 +41,7 @@ type AdminEditUserForm struct {
Password string `binding:"MaxSize(255)"`
Website string `binding:"ValidUrl;MaxSize(255)"`
Location string `binding:"MaxSize(50)"`
+ Language string `binding:"MaxSize(5)"`
MaxRepoCreation int
Active bool
Admin bool
diff --git a/services/migrations/gitea_uploader_test.go b/services/migrations/gitea_uploader_test.go
index c8102c6b8b71b..c9b924809819b 100644
--- a/services/migrations/gitea_uploader_test.go
+++ b/services/migrations/gitea_uploader_test.go
@@ -23,9 +23,9 @@ import (
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/log"
base "code.gitea.io/gitea/modules/migration"
+ "code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/test"
- "code.gitea.io/gitea/modules/util"
"github.com/stretchr/testify/assert"
)
@@ -68,14 +68,14 @@ func TestGiteaUploadRepo(t *testing.T) {
milestones, err := db.Find[issues_model.Milestone](db.DefaultContext, issues_model.FindMilestoneOptions{
RepoID: repo.ID,
- IsClosed: util.OptionalBoolFalse,
+ IsClosed: optional.Some(false),
})
assert.NoError(t, err)
assert.Len(t, milestones, 1)
milestones, err = db.Find[issues_model.Milestone](db.DefaultContext, issues_model.FindMilestoneOptions{
RepoID: repo.ID,
- IsClosed: util.OptionalBoolTrue,
+ IsClosed: optional.Some(true),
})
assert.NoError(t, err)
assert.Empty(t, milestones)
@@ -108,7 +108,7 @@ func TestGiteaUploadRepo(t *testing.T) {
issues, err := issues_model.Issues(db.DefaultContext, &issues_model.IssuesOptions{
RepoIDs: []int64{repo.ID},
- IsPull: util.OptionalBoolFalse,
+ IsPull: optional.Some(false),
SortType: "oldest",
})
assert.NoError(t, err)
diff --git a/services/packages/cleanup/cleanup.go b/services/packages/cleanup/cleanup.go
index 0ff8077bc9074..5d5120c6a0a87 100644
--- a/services/packages/cleanup/cleanup.go
+++ b/services/packages/cleanup/cleanup.go
@@ -12,8 +12,8 @@ import (
packages_model "code.gitea.io/gitea/models/packages"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/optional"
packages_module "code.gitea.io/gitea/modules/packages"
- "code.gitea.io/gitea/modules/util"
packages_service "code.gitea.io/gitea/services/packages"
alpine_service "code.gitea.io/gitea/services/packages/alpine"
cargo_service "code.gitea.io/gitea/services/packages/cargo"
@@ -60,7 +60,7 @@ func ExecuteCleanupRules(outerCtx context.Context) error {
for _, p := range packages {
pvs, _, err := packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{
PackageID: p.ID,
- IsInternal: util.OptionalBoolFalse,
+ IsInternal: optional.Some(false),
Sort: packages_model.SortCreatedDesc,
Paginator: db.NewAbsoluteListOptions(pcr.KeepCount, 200),
})
diff --git a/services/packages/container/cleanup.go b/services/packages/container/cleanup.go
index dd3f158dbf9ff..3f5f43bbc0bb1 100644
--- a/services/packages/container/cleanup.go
+++ b/services/packages/container/cleanup.go
@@ -9,8 +9,8 @@ import (
packages_model "code.gitea.io/gitea/models/packages"
container_model "code.gitea.io/gitea/models/packages/container"
+ "code.gitea.io/gitea/modules/optional"
container_module "code.gitea.io/gitea/modules/packages/container"
- "code.gitea.io/gitea/modules/util"
packages_service "code.gitea.io/gitea/services/packages"
digest "github.com/opencontainers/go-digest"
@@ -59,8 +59,8 @@ func cleanupExpiredUploadedBlobs(ctx context.Context, olderThan time.Duration) e
ExactMatch: true,
Value: container_model.UploadVersion,
},
- IsInternal: util.OptionalBoolTrue,
- HasFiles: util.OptionalBoolFalse,
+ IsInternal: optional.Some(true),
+ HasFiles: optional.Some(false),
})
if err != nil {
return err
diff --git a/services/packages/packages.go b/services/packages/packages.go
index 56d5cc04de2df..64b1ddd869632 100644
--- a/services/packages/packages.go
+++ b/services/packages/packages.go
@@ -18,10 +18,10 @@ import (
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/optional"
packages_module "code.gitea.io/gitea/modules/packages"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/storage"
- "code.gitea.io/gitea/modules/util"
notify_service "code.gitea.io/gitea/services/notify"
)
@@ -330,7 +330,7 @@ func CheckCountQuotaExceeded(ctx context.Context, doer, owner *user_model.User)
if setting.Packages.LimitTotalOwnerCount > -1 {
totalCount, err := packages_model.CountVersions(ctx, &packages_model.PackageSearchOptions{
OwnerID: owner.ID,
- IsInternal: util.OptionalBoolFalse,
+ IsInternal: optional.Some(false),
})
if err != nil {
log.Error("CountVersions failed: %v", err)
@@ -640,7 +640,7 @@ func RemoveAllPackages(ctx context.Context, userID int64) (int, error) {
Page: 1,
},
OwnerID: userID,
- IsInternal: util.OptionalBoolNone,
+ IsInternal: optional.None[bool](),
})
if err != nil {
return count, fmt.Errorf("GetOwnedPackages[%d]: %w", userID, err)
diff --git a/services/pull/review.go b/services/pull/review.go
index 3ffc276778c96..90d07c8358067 100644
--- a/services/pull/review.go
+++ b/services/pull/review.go
@@ -18,8 +18,8 @@ import (
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/modules/util"
notify_service "code.gitea.io/gitea/services/notify"
)
@@ -56,7 +56,7 @@ func InvalidateCodeComments(ctx context.Context, prs issues_model.PullRequestLis
ListAll: true,
},
Type: issues_model.CommentTypeCode,
- Invalidated: util.OptionalBoolFalse,
+ Invalidated: optional.Some(false),
IssueIDs: issueIDs,
})
if err != nil {
@@ -327,7 +327,7 @@ func DismissApprovalReviews(ctx context.Context, doer *user_model.User, pull *is
},
IssueID: pull.IssueID,
Type: issues_model.ReviewTypeApprove,
- Dismissed: util.OptionalBoolFalse,
+ Dismissed: optional.Some(false),
})
if err != nil {
return err
@@ -394,7 +394,7 @@ func DismissReview(ctx context.Context, reviewID, repoID int64, message string,
reviews, err := issues_model.FindReviews(ctx, issues_model.FindReviewOptions{
IssueID: review.IssueID,
ReviewerID: review.ReviewerID,
- Dismissed: util.OptionalBoolFalse,
+ Dismissed: optional.Some(false),
})
if err != nil {
return nil, err
diff --git a/services/repository/branch.go b/services/repository/branch.go
index ec41173da8c4f..55cedf5d84bfb 100644
--- a/services/repository/branch.go
+++ b/services/repository/branch.go
@@ -24,7 +24,6 @@ import (
"code.gitea.io/gitea/modules/queue"
repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/timeutil"
- "code.gitea.io/gitea/modules/util"
webhook_module "code.gitea.io/gitea/modules/webhook"
notify_service "code.gitea.io/gitea/services/notify"
files_service "code.gitea.io/gitea/services/repository/files"
@@ -54,7 +53,7 @@ type Branch struct {
}
// LoadBranches loads branches from the repository limited by page & pageSize.
-func LoadBranches(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, isDeletedBranch util.OptionalBool, keyword string, page, pageSize int) (*Branch, []*Branch, int64, error) {
+func LoadBranches(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, isDeletedBranch optional.Option[bool], keyword string, page, pageSize int) (*Branch, []*Branch, int64, error) {
defaultDBBranch, err := git_model.GetBranch(ctx, repo.ID, repo.DefaultBranch)
if err != nil {
return nil, nil, 0, err
@@ -62,7 +61,7 @@ func LoadBranches(ctx context.Context, repo *repo_model.Repository, gitRepo *git
branchOpts := git_model.FindBranchOptions{
RepoID: repo.ID,
- IsDeletedBranch: isDeletedBranch.ToGeneric(),
+ IsDeletedBranch: isDeletedBranch,
ListOptions: db.ListOptions{
Page: page,
PageSize: pageSize,
diff --git a/services/webhook/webhook.go b/services/webhook/webhook.go
index ac18da3525288..35c760dc62409 100644
--- a/services/webhook/webhook.go
+++ b/services/webhook/webhook.go
@@ -16,6 +16,7 @@ import (
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/queue"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
@@ -225,7 +226,7 @@ func PrepareWebhooks(ctx context.Context, source EventSource, event webhook_modu
if source.Repository != nil {
repoHooks, err := db.Find[webhook_model.Webhook](ctx, webhook_model.ListWebhookOptions{
RepoID: source.Repository.ID,
- IsActive: util.OptionalBoolTrue,
+ IsActive: optional.Some(true),
})
if err != nil {
return fmt.Errorf("ListWebhooksByOpts: %w", err)
@@ -239,7 +240,7 @@ func PrepareWebhooks(ctx context.Context, source EventSource, event webhook_modu
if owner != nil {
ownerHooks, err := db.Find[webhook_model.Webhook](ctx, webhook_model.ListWebhookOptions{
OwnerID: owner.ID,
- IsActive: util.OptionalBoolTrue,
+ IsActive: optional.Some(true),
})
if err != nil {
return fmt.Errorf("ListWebhooksByOpts: %w", err)
@@ -248,7 +249,7 @@ func PrepareWebhooks(ctx context.Context, source EventSource, event webhook_modu
}
// Add any admin-defined system webhooks
- systemHooks, err := webhook_model.GetSystemWebhooks(ctx, util.OptionalBoolTrue)
+ systemHooks, err := webhook_model.GetSystemWebhooks(ctx, optional.Some(true))
if err != nil {
return fmt.Errorf("GetSystemWebhooks: %w", err)
}
diff --git a/templates/admin/user/edit.tmpl b/templates/admin/user/edit.tmpl
index fcb8ce08277fb..159c8210993fc 100644
--- a/templates/admin/user/edit.tmpl
+++ b/templates/admin/user/edit.tmpl
@@ -70,6 +70,21 @@
{{ctx.Locale.Tr "admin.users.password_helper"}}
+ +